@modelprofile.com/flexharness 10.17.1 → 10.19.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/dist_ts/00_commitinfo_data.js +1 -1
- package/dist_ts/errors.d.ts +4 -0
- package/dist_ts/errors.js +9 -1
- package/dist_ts/functions.toolpermissions.d.ts +24 -0
- package/dist_ts/functions.toolpermissions.js +38 -0
- package/dist_ts/index.d.ts +1 -0
- package/dist_ts/index.js +2 -1
- package/dist_ts/plugins.d.ts +1 -1
- package/dist_ts/plugins.js +1 -1
- package/dist_ts_chat_harness/classes.chatclient.d.ts +95 -0
- package/dist_ts_chat_harness/classes.chatclient.js +263 -0
- package/dist_ts_chat_harness/classes.chatrequesterror.d.ts +4 -0
- package/dist_ts_chat_harness/classes.chatrequesterror.js +8 -0
- package/dist_ts_chat_harness/classes.transcript.d.ts +1 -1
- package/dist_ts_chat_harness/classes.transcript.js +1 -1
- package/dist_ts_chat_harness/functions.intents.d.ts +1 -2
- package/dist_ts_chat_harness/functions.intents.js +1 -1
- package/dist_ts_chat_harness/functions.mapping.d.ts +1 -1
- package/dist_ts_chat_harness/functions.mapping.js +1 -1
- package/dist_ts_chat_harness/index.d.ts +3 -0
- package/dist_ts_chat_harness/index.js +3 -1
- package/dist_ts_chat_harness/interfaces.chat.d.ts +136 -0
- package/dist_ts_chat_harness/interfaces.chat.js +2 -0
- package/dist_ts_chat_harness/plugins.js +1 -1
- package/dist_ts_chat_harness_server/classes.chathub.d.ts +78 -0
- package/dist_ts_chat_harness_server/classes.chathub.js +332 -0
- package/dist_ts_chat_harness_server/classes.chatsubscription.d.ts +55 -0
- package/dist_ts_chat_harness_server/classes.chatsubscription.js +236 -0
- package/dist_ts_chat_harness_server/classes.sessionlists.d.ts +21 -0
- package/dist_ts_chat_harness_server/classes.sessionlists.js +70 -0
- package/dist_ts_chat_harness_server/classes.turngate.d.ts +38 -0
- package/dist_ts_chat_harness_server/classes.turngate.js +207 -0
- package/dist_ts_chat_harness_server/errors.d.ts +5 -0
- package/dist_ts_chat_harness_server/errors.js +9 -0
- package/dist_ts_chat_harness_server/functions.errorprojector.d.ts +11 -0
- package/dist_ts_chat_harness_server/functions.errorprojector.js +32 -0
- package/dist_ts_chat_harness_server/functions.validation.d.ts +18 -0
- package/dist_ts_chat_harness_server/functions.validation.js +88 -0
- package/dist_ts_chat_harness_server/index.d.ts +4 -0
- package/dist_ts_chat_harness_server/index.js +4 -0
- package/dist_ts_chat_harness_server/interfaces.d.ts +67 -0
- package/dist_ts_chat_harness_server/interfaces.js +2 -0
- package/dist_ts_chat_harness_server/plugins.d.ts +7 -0
- package/dist_ts_chat_harness_server/plugins.js +6 -0
- package/dist_ts_chat_harness_typedsocket/classes.clienttransport.d.ts +22 -0
- package/dist_ts_chat_harness_typedsocket/classes.clienttransport.js +55 -0
- package/dist_ts_chat_harness_typedsocket/classes.serverbinding.d.ts +46 -0
- package/dist_ts_chat_harness_typedsocket/classes.serverbinding.js +110 -0
- package/dist_ts_chat_harness_typedsocket/index.d.ts +3 -0
- package/dist_ts_chat_harness_typedsocket/index.js +3 -0
- package/dist_ts_chat_harness_typedsocket/interfaces.requests.d.ts +38 -0
- package/dist_ts_chat_harness_typedsocket/interfaces.requests.js +2 -0
- package/dist_ts_chat_harness_typedsocket/plugins.d.ts +9 -0
- package/dist_ts_chat_harness_typedsocket/plugins.js +8 -0
- package/dist_ts_ocr/ocr.mistral.d.ts +20 -1
- package/dist_ts_ocr/ocr.mistral.js +66 -43
- package/dist_ts_tools/tool.filesystem.d.ts +2 -0
- package/dist_ts_tools/tool.filesystem.js +42 -1
- package/dist_ts_tools_node/classes.workspacereversion.d.ts +48 -0
- package/dist_ts_tools_node/classes.workspacereversion.js +202 -0
- package/dist_ts_tools_node/functions.fileimages.d.ts +22 -0
- package/dist_ts_tools_node/functions.fileimages.js +87 -0
- package/dist_ts_tools_node/index.d.ts +3 -1
- package/dist_ts_tools_node/index.js +2 -1
- package/dist_ts_tools_node/plugins.d.ts +1 -0
- package/dist_ts_tools_node/tool.context.d.ts +20 -0
- package/dist_ts_tools_node/tool.context.js +25 -4
- package/package.json +28 -4
- package/ts/00_commitinfo_data.ts +1 -1
- package/ts/errors.ts +10 -0
- package/ts/functions.toolpermissions.ts +60 -0
- package/ts/index.ts +6 -0
- package/ts/plugins.ts +1 -0
- package/ts_chat_harness/classes.chatclient.ts +343 -0
- package/ts_chat_harness/classes.chatrequesterror.ts +7 -0
- package/ts_chat_harness/classes.transcript.ts +1 -1
- package/ts_chat_harness/functions.intents.ts +2 -2
- package/ts_chat_harness/functions.mapping.ts +1 -1
- package/ts_chat_harness/index.ts +20 -0
- package/ts_chat_harness/interfaces.chat.ts +108 -0
- package/ts_chat_harness/readme.md +24 -0
- package/ts_chat_harness_server/classes.chathub.ts +400 -0
- package/ts_chat_harness_server/classes.chatsubscription.ts +257 -0
- package/ts_chat_harness_server/classes.sessionlists.ts +90 -0
- package/ts_chat_harness_server/classes.turngate.ts +247 -0
- package/ts_chat_harness_server/errors.ts +9 -0
- package/ts_chat_harness_server/functions.errorprojector.ts +40 -0
- package/ts_chat_harness_server/functions.validation.ts +104 -0
- package/ts_chat_harness_server/index.ts +19 -0
- package/ts_chat_harness_server/interfaces.ts +92 -0
- package/ts_chat_harness_server/plugins.ts +62 -0
- package/ts_chat_harness_server/readme.md +91 -0
- package/ts_chat_harness_typedsocket/classes.clienttransport.ts +87 -0
- package/ts_chat_harness_typedsocket/classes.serverbinding.ts +172 -0
- package/ts_chat_harness_typedsocket/index.ts +17 -0
- package/ts_chat_harness_typedsocket/interfaces.requests.ts +40 -0
- package/ts_chat_harness_typedsocket/plugins.ts +28 -0
- package/ts_chat_harness_typedsocket/readme.md +57 -0
- package/ts_ocr/ocr.mistral.ts +102 -49
- package/ts_ocr/readme.md +12 -1
- package/ts_tools/readme.md +10 -0
- package/ts_tools/tool.filesystem.ts +55 -0
- package/ts_tools_node/classes.workspacereversion.ts +255 -0
- package/ts_tools_node/functions.fileimages.ts +89 -0
- package/ts_tools_node/index.ts +7 -1
- package/ts_tools_node/plugins.ts +11 -0
- package/ts_tools_node/readme.md +27 -0
- package/ts_tools_node/tool.context.ts +49 -3
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type * as plugins from './plugins.js';
|
|
2
|
+
import type { IFlexHarnessChatCaller, IFlexHarnessChatPeers } from './interfaces.js';
|
|
3
|
+
type TSessionEvent = plugins.IFlexSessionCreatedEvent | plugins.IFlexSessionUpdatedEvent | plugins.IFlexSessionDeletedEvent;
|
|
4
|
+
/**
|
|
5
|
+
* The conversation lists of the attached tabs: a conversation created, changed or deleted in a
|
|
6
|
+
* tab's scope reaches the tab as a push. Pushes are best effort; a tab that misses one attaches
|
|
7
|
+
* again after it reconnects and gets the whole list.
|
|
8
|
+
*/
|
|
9
|
+
export declare class FlexHarnessChatSessionLists {
|
|
10
|
+
private readonly peers;
|
|
11
|
+
private readonly toSessionMeta;
|
|
12
|
+
private readonly attached;
|
|
13
|
+
constructor(peersArg: IFlexHarnessChatPeers, toSessionMetaArg: (sessionArg: plugins.IFlexSession) => plugins.IHarnessSessionMeta);
|
|
14
|
+
get tabs(): IFlexHarnessChatCaller[];
|
|
15
|
+
attach(tabArg: IFlexHarnessChatCaller): void;
|
|
16
|
+
forget(tabArg: IFlexHarnessChatCaller): void;
|
|
17
|
+
clear(): void;
|
|
18
|
+
publish(eventArg: TSessionEvent): void;
|
|
19
|
+
private pump;
|
|
20
|
+
}
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { tabKey } from './functions.validation.js';
|
|
2
|
+
/**
|
|
3
|
+
* The conversation lists of the attached tabs: a conversation created, changed or deleted in a
|
|
4
|
+
* tab's scope reaches the tab as a push. Pushes are best effort; a tab that misses one attaches
|
|
5
|
+
* again after it reconnects and gets the whole list.
|
|
6
|
+
*/
|
|
7
|
+
export class FlexHarnessChatSessionLists {
|
|
8
|
+
peers;
|
|
9
|
+
toSessionMeta;
|
|
10
|
+
attached = new Map();
|
|
11
|
+
constructor(peersArg, toSessionMetaArg) {
|
|
12
|
+
this.peers = peersArg;
|
|
13
|
+
this.toSessionMeta = toSessionMetaArg;
|
|
14
|
+
}
|
|
15
|
+
get tabs() {
|
|
16
|
+
return [...this.attached.values()].map((entry) => entry.tab);
|
|
17
|
+
}
|
|
18
|
+
attach(tabArg) {
|
|
19
|
+
this.attached.set(tabKey(tabArg), {
|
|
20
|
+
tab: { tabId: tabArg.tabId, scopeId: tabArg.scopeId },
|
|
21
|
+
upserts: new Map(),
|
|
22
|
+
deletedIds: new Set(),
|
|
23
|
+
sending: false,
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
forget(tabArg) {
|
|
27
|
+
this.attached.delete(tabKey(tabArg));
|
|
28
|
+
}
|
|
29
|
+
clear() {
|
|
30
|
+
this.attached.clear();
|
|
31
|
+
}
|
|
32
|
+
publish(eventArg) {
|
|
33
|
+
for (const [key, entry] of this.attached) {
|
|
34
|
+
if (entry.tab.scopeId !== eventArg.scopeId)
|
|
35
|
+
continue;
|
|
36
|
+
if (eventArg.type === 'session.deleted') {
|
|
37
|
+
entry.upserts.delete(eventArg.sessionId);
|
|
38
|
+
entry.deletedIds.add(eventArg.sessionId);
|
|
39
|
+
}
|
|
40
|
+
else {
|
|
41
|
+
entry.deletedIds.delete(eventArg.sessionId);
|
|
42
|
+
entry.upserts.set(eventArg.sessionId, this.toSessionMeta(eventArg.session));
|
|
43
|
+
}
|
|
44
|
+
void this.pump(key, entry);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
async pump(keyArg, entryArg) {
|
|
48
|
+
if (entryArg.sending)
|
|
49
|
+
return;
|
|
50
|
+
entryArg.sending = true;
|
|
51
|
+
try {
|
|
52
|
+
while (entryArg.upserts.size || entryArg.deletedIds.size) {
|
|
53
|
+
const peer = await this.peers.find(entryArg.tab).catch(() => null);
|
|
54
|
+
if (!peer) {
|
|
55
|
+
if (this.attached.get(keyArg) === entryArg)
|
|
56
|
+
this.attached.delete(keyArg);
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
const push = { upserts: [...entryArg.upserts.values()], deletedIds: [...entryArg.deletedIds] };
|
|
60
|
+
entryArg.upserts.clear();
|
|
61
|
+
entryArg.deletedIds.clear();
|
|
62
|
+
await peer.sessions(push).catch(() => undefined);
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
finally {
|
|
66
|
+
entryArg.sending = false;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy5zZXNzaW9ubGlzdHMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19jaGF0X2hhcm5lc3Nfc2VydmVyL2NsYXNzZXMuc2Vzc2lvbmxpc3RzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSxNQUFNLEVBQUUsTUFBTSwyQkFBMkIsQ0FBQztBQWdCbkQ7Ozs7R0FJRztBQUNILE1BQU0sT0FBTywyQkFBMkI7SUFDckIsS0FBSyxDQUF3QjtJQUM3QixhQUFhLENBQW9FO0lBQ2pGLFFBQVEsR0FBRyxJQUFJLEdBQUcsRUFBd0IsQ0FBQztJQUU1RCxZQUNFLFFBQStCLEVBQy9CLGdCQUFtRjtRQUVuRixJQUFJLENBQUMsS0FBSyxHQUFHLFFBQVEsQ0FBQztRQUN0QixJQUFJLENBQUMsYUFBYSxHQUFHLGdCQUFnQixDQUFDO0lBQ3hDLENBQUM7SUFFRCxJQUFXLElBQUk7UUFDYixPQUFPLENBQUMsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxFQUFFLEVBQUUsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUM7SUFDL0QsQ0FBQztJQUVNLE1BQU0sQ0FBQyxNQUE4QjtRQUMxQyxJQUFJLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEVBQUU7WUFDaEMsR0FBRyxFQUFFLEVBQUUsS0FBSyxFQUFFLE1BQU0sQ0FBQyxLQUFLLEVBQUUsT0FBTyxFQUFFLE1BQU0sQ0FBQyxPQUFPLEVBQUU7WUFDckQsT0FBTyxFQUFFLElBQUksR0FBRyxFQUFFO1lBQ2xCLFVBQVUsRUFBRSxJQUFJLEdBQUcsRUFBRTtZQUNyQixPQUFPLEVBQUUsS0FBSztTQUNmLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFTSxNQUFNLENBQUMsTUFBOEI7UUFDMUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLE1B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
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import type { IFlexHarnessChatCaller, IFlexHarnessChatLimits, IFlexHarnessChatTurn } from './interfaces.js';
|
|
3
|
+
/** The harness calls the gate makes. */
|
|
4
|
+
export type TFlexHarnessChatGateHarness = Pick<plugins.FlexHarness<unknown>, 'enqueuePrompt' | 'steerPrompt' | 'getPromptQueueEntry' | 'cancelPrompt'>;
|
|
5
|
+
/**
|
|
6
|
+
* Admits messages: one turn per conversation, bound to the tab that started it and the context it
|
|
7
|
+
* was sent with, since FlexHarness carries no per-prompt context. A message sent while a turn runs
|
|
8
|
+
* steers it; a steer the turn no longer takes waits for the ending turn and starts the next one.
|
|
9
|
+
*/
|
|
10
|
+
export declare class FlexHarnessChatTurnGate<TContext> {
|
|
11
|
+
private readonly harness;
|
|
12
|
+
private readonly limits;
|
|
13
|
+
private readonly bindings;
|
|
14
|
+
/** serializes the admission of messages per conversation */
|
|
15
|
+
private readonly locks;
|
|
16
|
+
/** the admissions under way, each settling once its message was admitted or refused */
|
|
17
|
+
private readonly admissions;
|
|
18
|
+
private stopped;
|
|
19
|
+
constructor(harnessArg: TFlexHarnessChatGateHarness, limitsArg: IFlexHarnessChatLimits);
|
|
20
|
+
turnOf(scopeIdArg: string, sessionIdArg: string): IFlexHarnessChatTurn<TContext> | undefined;
|
|
21
|
+
/** Whether a turn the tab started still runs. */
|
|
22
|
+
hasTurnOf(tabArg: IFlexHarnessChatCaller): boolean;
|
|
23
|
+
/** Takes one harness event: a prompt that runs now takes steers. */
|
|
24
|
+
takeEvent(eventArg: plugins.TFlexHarnessEvent): void;
|
|
25
|
+
/** Admits a message under the conversation's lock; every wait ends at the deadline. */
|
|
26
|
+
admit(callerArg: IFlexHarnessChatCaller, sessionIdArg: string, sendArg: plugins.IHarnessComposerSendDetail, contextArg: TContext, deadlineArg: number): Promise<plugins.TFlexHarnessChatResponse<'flexHarnessChatSend'>>;
|
|
27
|
+
/**
|
|
28
|
+
* Refuses new messages, stops every turn this gate started, also those admitted while it stops,
|
|
29
|
+
* and waits until the admissions under way were refused and every turn ended.
|
|
30
|
+
*/
|
|
31
|
+
stop(): Promise<void>;
|
|
32
|
+
private cancelTurns;
|
|
33
|
+
private cancel;
|
|
34
|
+
private assertOpen;
|
|
35
|
+
private withLock;
|
|
36
|
+
private admitLocked;
|
|
37
|
+
private startTurn;
|
|
38
|
+
}
|
|
@@ -0,0 +1,207 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { FlexHarnessChatRequestError } from './errors.js';
|
|
3
|
+
import { STOPPED_MESSAGE } from './functions.validation.js';
|
|
4
|
+
const STILL_FINISHING_MESSAGE = 'The assistant is still finishing its previous reply. Send your message again in a moment.';
|
|
5
|
+
const bindingKey = (scopeIdArg, sessionIdArg) => `${scopeIdArg}\n${sessionIdArg}`;
|
|
6
|
+
/** Whether the promise settled before the deadline (a time in ms since the epoch). */
|
|
7
|
+
const settlesBefore = async (promiseArg, deadlineArg) => {
|
|
8
|
+
let timer;
|
|
9
|
+
const expired = new Promise((resolve) => {
|
|
10
|
+
timer = setTimeout(() => resolve(false), Math.max(0, deadlineArg - Date.now()));
|
|
11
|
+
});
|
|
12
|
+
try {
|
|
13
|
+
return await Promise.race([promiseArg.then(() => true, () => true), expired]);
|
|
14
|
+
}
|
|
15
|
+
finally {
|
|
16
|
+
clearTimeout(timer);
|
|
17
|
+
}
|
|
18
|
+
};
|
|
19
|
+
/**
|
|
20
|
+
* Admits messages: one turn per conversation, bound to the tab that started it and the context it
|
|
21
|
+
* was sent with, since FlexHarness carries no per-prompt context. A message sent while a turn runs
|
|
22
|
+
* steers it; a steer the turn no longer takes waits for the ending turn and starts the next one.
|
|
23
|
+
*/
|
|
24
|
+
export class FlexHarnessChatTurnGate {
|
|
25
|
+
harness;
|
|
26
|
+
limits;
|
|
27
|
+
bindings = new Map();
|
|
28
|
+
/** serializes the admission of messages per conversation */
|
|
29
|
+
locks = new Map();
|
|
30
|
+
/** the admissions under way, each settling once its message was admitted or refused */
|
|
31
|
+
admissions = new Set();
|
|
32
|
+
stopped = false;
|
|
33
|
+
constructor(harnessArg, limitsArg) {
|
|
34
|
+
this.harness = harnessArg;
|
|
35
|
+
this.limits = limitsArg;
|
|
36
|
+
}
|
|
37
|
+
turnOf(scopeIdArg, sessionIdArg) {
|
|
38
|
+
const binding = this.bindings.get(bindingKey(scopeIdArg, sessionIdArg));
|
|
39
|
+
return binding
|
|
40
|
+
? { scopeId: binding.scopeId, sessionId: binding.sessionId, tabId: binding.tabId, context: binding.context }
|
|
41
|
+
: undefined;
|
|
42
|
+
}
|
|
43
|
+
/** Whether a turn the tab started still runs. */
|
|
44
|
+
hasTurnOf(tabArg) {
|
|
45
|
+
for (const binding of this.bindings.values()) {
|
|
46
|
+
if (binding.tabId === tabArg.tabId && binding.scopeId === tabArg.scopeId)
|
|
47
|
+
return true;
|
|
48
|
+
}
|
|
49
|
+
return false;
|
|
50
|
+
}
|
|
51
|
+
/** Takes one harness event: a prompt that runs now takes steers. */
|
|
52
|
+
takeEvent(eventArg) {
|
|
53
|
+
if (eventArg.type !== 'prompt.running' && eventArg.type !== 'prompt.finished')
|
|
54
|
+
return;
|
|
55
|
+
const binding = this.bindings.get(bindingKey(eventArg.scopeId, eventArg.sessionId));
|
|
56
|
+
if (binding && binding.queueId === eventArg.queueId)
|
|
57
|
+
binding.markRunning();
|
|
58
|
+
}
|
|
59
|
+
/** Admits a message under the conversation's lock; every wait ends at the deadline. */
|
|
60
|
+
admit(callerArg, sessionIdArg, sendArg, contextArg, deadlineArg) {
|
|
61
|
+
if (this.stopped)
|
|
62
|
+
return Promise.reject(new FlexHarnessChatRequestError(STOPPED_MESSAGE));
|
|
63
|
+
const admission = this.withLock(bindingKey(callerArg.scopeId, sessionIdArg), () => this.admitLocked(callerArg, sessionIdArg, sendArg, contextArg, deadlineArg));
|
|
64
|
+
const settled = admission.then(() => undefined, () => undefined);
|
|
65
|
+
this.admissions.add(settled);
|
|
66
|
+
void settled.then(() => this.admissions.delete(settled));
|
|
67
|
+
return admission;
|
|
68
|
+
}
|
|
69
|
+
/**
|
|
70
|
+
* Refuses new messages, stops every turn this gate started, also those admitted while it stops,
|
|
71
|
+
* and waits until the admissions under way were refused and every turn ended.
|
|
72
|
+
*/
|
|
73
|
+
async stop() {
|
|
74
|
+
this.stopped = true;
|
|
75
|
+
this.cancelTurns();
|
|
76
|
+
await Promise.all([...this.admissions]);
|
|
77
|
+
// a turn whose prompt was being queued when the gate stopped was cancelled by its admission
|
|
78
|
+
this.cancelTurns();
|
|
79
|
+
await Promise.all([...this.bindings.values()].map((binding) => binding.settled));
|
|
80
|
+
}
|
|
81
|
+
cancelTurns() {
|
|
82
|
+
for (const binding of this.bindings.values()) {
|
|
83
|
+
clearTimeout(binding.timer);
|
|
84
|
+
if (binding.queueId)
|
|
85
|
+
this.cancel(binding.scopeId, binding.sessionId, binding.queueId);
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
cancel(scopeIdArg, sessionIdArg, queueIdArg) {
|
|
89
|
+
void this.harness.cancelPrompt(scopeIdArg, sessionIdArg, queueIdArg).catch(() => false);
|
|
90
|
+
}
|
|
91
|
+
assertOpen() {
|
|
92
|
+
if (this.stopped)
|
|
93
|
+
throw new FlexHarnessChatRequestError(STOPPED_MESSAGE);
|
|
94
|
+
}
|
|
95
|
+
async withLock(keyArg, fnArg) {
|
|
96
|
+
const previous = this.locks.get(keyArg) ?? Promise.resolve();
|
|
97
|
+
let release;
|
|
98
|
+
const current = new Promise((resolve) => (release = resolve));
|
|
99
|
+
const chained = previous.then(() => current);
|
|
100
|
+
this.locks.set(keyArg, chained);
|
|
101
|
+
await previous;
|
|
102
|
+
try {
|
|
103
|
+
return await fnArg();
|
|
104
|
+
}
|
|
105
|
+
finally {
|
|
106
|
+
release();
|
|
107
|
+
if (this.locks.get(keyArg) === chained)
|
|
108
|
+
this.locks.delete(keyArg);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
async admitLocked(callerArg, sessionIdArg, sendArg, contextArg, deadlineArg) {
|
|
112
|
+
const waitFor = async (promiseArg) => {
|
|
113
|
+
if (!(await settlesBefore(promiseArg, deadlineArg)))
|
|
114
|
+
throw new FlexHarnessChatRequestError(STILL_FINISHING_MESSAGE);
|
|
115
|
+
};
|
|
116
|
+
this.assertOpen();
|
|
117
|
+
const target = { scopeId: callerArg.scopeId, sessionId: sessionIdArg };
|
|
118
|
+
const binding = this.bindings.get(bindingKey(target.scopeId, target.sessionId));
|
|
119
|
+
if (binding?.queueId) {
|
|
120
|
+
for (let attempt = 0; attempt < 2; attempt++) {
|
|
121
|
+
const intent = intentOf(target, { ...sendArg, delivery: 'steer' }, binding.queueId);
|
|
122
|
+
if (intent.type !== 'steerPrompt')
|
|
123
|
+
break;
|
|
124
|
+
this.assertOpen();
|
|
125
|
+
try {
|
|
126
|
+
await this.harness.steerPrompt(target.scopeId, target.sessionId, intent.queueId, {
|
|
127
|
+
steerId: intent.steerId,
|
|
128
|
+
prompt: intent.prompt,
|
|
129
|
+
});
|
|
130
|
+
return { sessionId: sessionIdArg, steerId: intent.steerId };
|
|
131
|
+
}
|
|
132
|
+
catch (error) {
|
|
133
|
+
if (!(error instanceof plugins.FlexHarnessSteerRejectedError) || error.reason !== 'not-running')
|
|
134
|
+
throw error;
|
|
135
|
+
}
|
|
136
|
+
// a prompt still waiting for its run takes steers once it runs
|
|
137
|
+
const entry = await this.harness
|
|
138
|
+
.getPromptQueueEntry(target.scopeId, target.sessionId, binding.queueId)
|
|
139
|
+
.catch(() => undefined);
|
|
140
|
+
if (!entry || !['queued', 'starting', 'scheduled'].includes(entry.status))
|
|
141
|
+
break;
|
|
142
|
+
await waitFor(Promise.race([binding.running, binding.settled]));
|
|
143
|
+
}
|
|
144
|
+
await waitFor(binding.settled);
|
|
145
|
+
}
|
|
146
|
+
else if (binding) {
|
|
147
|
+
await waitFor(binding.settled);
|
|
148
|
+
}
|
|
149
|
+
this.assertOpen();
|
|
150
|
+
return this.startTurn(callerArg, sessionIdArg, sendArg, contextArg);
|
|
151
|
+
}
|
|
152
|
+
async startTurn(callerArg, sessionIdArg, sendArg, contextArg) {
|
|
153
|
+
const key = bindingKey(callerArg.scopeId, sessionIdArg);
|
|
154
|
+
const intent = intentOf({ scopeId: callerArg.scopeId, sessionId: sessionIdArg }, { ...sendArg, delivery: 'turn' });
|
|
155
|
+
if (intent.type !== 'enqueuePrompt')
|
|
156
|
+
throw new Error('A new turn must be queued.');
|
|
157
|
+
let markSettled;
|
|
158
|
+
let markRunning;
|
|
159
|
+
const binding = {
|
|
160
|
+
scopeId: callerArg.scopeId,
|
|
161
|
+
sessionId: sessionIdArg,
|
|
162
|
+
tabId: callerArg.tabId,
|
|
163
|
+
context: contextArg,
|
|
164
|
+
running: new Promise((resolve) => (markRunning = resolve)),
|
|
165
|
+
markRunning: () => markRunning(),
|
|
166
|
+
settled: new Promise((resolve) => (markSettled = resolve)),
|
|
167
|
+
};
|
|
168
|
+
const end = () => {
|
|
169
|
+
clearTimeout(binding.timer);
|
|
170
|
+
if (this.bindings.get(key) === binding)
|
|
171
|
+
this.bindings.delete(key);
|
|
172
|
+
markRunning();
|
|
173
|
+
markSettled();
|
|
174
|
+
};
|
|
175
|
+
// bound before the prompt is queued: the model resolver may run at once
|
|
176
|
+
this.bindings.set(key, binding);
|
|
177
|
+
let queued;
|
|
178
|
+
try {
|
|
179
|
+
queued = await this.harness.enqueuePrompt(callerArg.scopeId, sessionIdArg, intent.prompt);
|
|
180
|
+
}
|
|
181
|
+
catch (error) {
|
|
182
|
+
end();
|
|
183
|
+
throw error;
|
|
184
|
+
}
|
|
185
|
+
binding.queueId = queued.queueId;
|
|
186
|
+
// the outcome of a turn is in its conversation; a failed turn is not an error of this request
|
|
187
|
+
void queued.completion.then(() => undefined, () => undefined).finally(end);
|
|
188
|
+
if (this.stopped) {
|
|
189
|
+
// the gate stopped while the prompt was being queued: the turn never runs on
|
|
190
|
+
this.cancel(callerArg.scopeId, sessionIdArg, queued.queueId);
|
|
191
|
+
throw new FlexHarnessChatRequestError(STOPPED_MESSAGE);
|
|
192
|
+
}
|
|
193
|
+
binding.timer = setTimeout(() => this.cancel(callerArg.scopeId, sessionIdArg, queued.queueId), this.limits.turnTimeoutMs);
|
|
194
|
+
binding.timer.unref?.();
|
|
195
|
+
return { sessionId: sessionIdArg, queueId: queued.queueId };
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/** The harness call a composer message becomes; an attachment the composer could not read whole is refused. */
|
|
199
|
+
const intentOf = (targetArg, sendArg, activeQueueIdArg) => {
|
|
200
|
+
try {
|
|
201
|
+
return plugins.flexHarnessSendIntent(targetArg, sendArg, activeQueueIdArg ? { activeQueueId: activeQueueIdArg } : {});
|
|
202
|
+
}
|
|
203
|
+
catch (error) {
|
|
204
|
+
throw new FlexHarnessChatRequestError(error?.message || 'The message could not be read.');
|
|
205
|
+
}
|
|
206
|
+
};
|
|
207
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2xhc3Nlcy50dXJuZ2F0ZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3RzX2NoYXRfaGFybmVzc19zZXJ2ZXIvY2xhc3Nlcy50dXJuZ2F0ZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEtBQUssT0FBTyxNQUFNLGNBQWMsQ0FBQztBQUN4QyxPQUFPLEVBQUUsMkJBQTJCLEVBQUUsTUFBTSxhQUFhLENBQUM7QUFDMUQsT0FBTyxFQUFFLGVBQWUsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBRzVELE1BQU0sdUJBQXVCLEdBQzNCLDJGQUEyRixDQUFDO0FBb0I5RixNQUFNLFVBQVUsR0FBRyxDQUFDLFVBQWtCLEVBQUUsWUFBb0IsRUFBRSxFQUFFLENBQUMsR0FBRyxVQUFVLEtBQUssWUFBWSxFQUFFLENBQUM7QUFFbEcsc0ZBQXNGO0FBQ3RGLE1BQU0sYUFBYSxHQUFHLEtBQUssRUFBRSxVQUE0QixFQUFFLFdBQW1CLEVBQW9CLEVBQUU7SUFDbEcsSUFBSSxLQUFnRCxDQUFDO0lBQ3JELE1BQU0sT0FBTyxHQUFHLElBQUksT0FBTyxDQUFRLENBQUMsT0FBTyxFQUFFLEVBQUU7UUFDN0MsS0FBSyxHQUFHLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsV0FBVyxHQUFHLElBQUksQ0FBQyxHQUFHLEVBQUUsQ0FBQyxDQUFDLENBQUM7SUFDbEYsQ0FBQyxDQUFDLENBQUM7SUFDSCxJQUFJLENBQUM7UUFDSCxPQUFPLE1BQU0sT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBYSxFQUFFLEdBQUcsRUFBRSxDQUFDLElBQWEsQ0FBQyxFQUFFLE9BQU8sQ0FBQyxDQUFDLENBQUM7SUFDbEcsQ0FBQztZQUFTLENBQUM7UUFDVCxZQUFZLENBQUMsS0FBSyxDQUFDLENBQUM7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
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export { FlexHarnessChatRequestError } from './plugins.js';
|
|
2
|
+
/** The tab of a turn is gone or did not answer a tool call in time. */
|
|
3
|
+
export class FlexHarnessChatTabUnavailableError extends Error {
|
|
4
|
+
constructor(options) {
|
|
5
|
+
super('The tab that started this turn is closed, lost its connection or did not answer in time.', options);
|
|
6
|
+
this.name = 'FlexHarnessChatTabUnavailableError';
|
|
7
|
+
}
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZXJyb3JzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHNfY2hhdF9oYXJuZXNzX3NlcnZlci9lcnJvcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLDJCQUEyQixFQUFFLE1BQU0sY0FBYyxDQUFDO0FBRTNELHVFQUF1RTtBQUN2RSxNQUFNLE9BQU8sa0NBQW1DLFNBQVEsS0FBSztJQUMzRCxZQUFZLE9BQXNCO1FBQ2hDLEtBQUssQ0FBQywwRkFBMEYsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUMzRyxJQUFJLENBQUMsSUFBSSxHQUFHLG9DQUFvQyxDQUFDO0lBQ25ELENBQUM7Q0FDRiJ9
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
export interface IFlexHarnessChatErrorProjectorOptions {
|
|
3
|
+
/** The host's own projection, tried first; return `undefined` for errors it does not know. */
|
|
4
|
+
project?: (error: unknown, context: plugins.IFlexExternalErrorContext) => plugins.IFlexErrorInfo | undefined;
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* An `externalErrorProjector` for chat conversations: what a failed model call, tool or resolver
|
|
8
|
+
* shows in the conversation, never a provider's response text. The host's projection comes first;
|
|
9
|
+
* then a tab that is gone, a model limit, an HTTP status of the model provider, and a fixed message.
|
|
10
|
+
*/
|
|
11
|
+
export declare function createFlexHarnessChatErrorProjector(options?: IFlexHarnessChatErrorProjectorOptions): plugins.TFlexExternalErrorProjector;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import * as plugins from './plugins.js';
|
|
2
|
+
import { FlexHarnessChatTabUnavailableError } from './errors.js';
|
|
3
|
+
/**
|
|
4
|
+
* An `externalErrorProjector` for chat conversations: what a failed model call, tool or resolver
|
|
5
|
+
* shows in the conversation, never a provider's response text. The host's projection comes first;
|
|
6
|
+
* then a tab that is gone, a model limit, an HTTP status of the model provider, and a fixed message.
|
|
7
|
+
*/
|
|
8
|
+
export function createFlexHarnessChatErrorProjector(options = {}) {
|
|
9
|
+
return (error, context) => {
|
|
10
|
+
const projected = options.project?.(error, context);
|
|
11
|
+
if (projected)
|
|
12
|
+
return projected;
|
|
13
|
+
if (error instanceof FlexHarnessChatTabUnavailableError) {
|
|
14
|
+
return { name: 'TabUnavailable', message: error.message, code: 'FLEX_CHAT_TAB_UNAVAILABLE' };
|
|
15
|
+
}
|
|
16
|
+
const limit = plugins.modelLimitErrorInfo(error);
|
|
17
|
+
if (limit)
|
|
18
|
+
return limit;
|
|
19
|
+
if (context.source === 'agentSession') {
|
|
20
|
+
const failure = plugins.describeModelFailure(error);
|
|
21
|
+
if (failure.kind === 'http' && failure.status) {
|
|
22
|
+
return {
|
|
23
|
+
name: 'ModelProviderError',
|
|
24
|
+
message: `The model provider answered with HTTP ${failure.status}.`,
|
|
25
|
+
code: 'FLEX_CHAT_MODEL_HTTP_ERROR',
|
|
26
|
+
};
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return { name: 'AssistantError', message: 'The assistant could not complete that request.', code: 'FLEX_CHAT_FAILED' };
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnVuY3Rpb25zLmVycm9ycHJvamVjdG9yLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vdHNfY2hhdF9oYXJuZXNzX3NlcnZlci9mdW5jdGlvbnMuZXJyb3Jwcm9qZWN0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxLQUFLLE9BQU8sTUFBTSxjQUFjLENBQUM7QUFDeEMsT0FBTyxFQUFFLGtDQUFrQyxFQUFFLE1BQU0sYUFBYSxDQUFDO0FBVWpFOzs7O0dBSUc7QUFDSCxNQUFNLFVBQVUsbUNBQW1DLENBQ2pELFVBQWlELEVBQUU7SUFFbkQsT0FBTyxDQUFDLEtBQUssRUFBRSxPQUFPLEVBQUUsRUFBRTtRQUN4QixNQUFNLFNBQVMsR0FBRyxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUMsS0FBSyxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3BELElBQUksU0FBUztZQUFFLE9BQU8sU0FBUyxDQUFDO1FBQ2hDLElBQUksS0FBSyxZQUFZLGtDQUFrQyxFQUFFLENBQUM7WUFDeEQsT0FBTyxFQUFFLElBQUksRUFBRSxnQkFBZ0IsRUFBRSxPQUFPLEVBQUUsS0FBSyxDQUFDLE9BQU8sRUFBRSxJQUFJLEVBQUUsMkJBQTJCLEVBQUUsQ0FBQztRQUMvRixDQUFDO1FBQ0QsTUFBTSxLQUFLLEdBQUcsT0FBTyxDQUFDLG1CQUFtQixDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQ2pELElBQUksS0FBSztZQUFFLE9BQU8sS0FBSyxDQUFDO1FBQ3hCLElBQUksT0FBTyxDQUFDLE1BQU0sS0FBSyxjQUFjLEVBQUUsQ0FBQztZQUN0QyxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsb0JBQW9CLENBQUMsS0FBSyxDQUFDLENBQUM7WUFDcEQsSUFBSSxPQUFPLENBQUMsSUFBSSxLQUFLLE1BQU0sSUFBSSxPQUFPLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQzlDLE9BQU87b0JBQ0wsSUFBSSxFQUFFLG9CQUFvQjtvQkFDMUIsT0FBTyxFQUFFLHlDQUF5QyxPQUFPLENBQUMsTUFBTSxHQUFHO29CQUNuRSxJQUFJLEVBQUUsNEJBQTRCO2lCQUNuQyxDQUFDO1lBQ0osQ0FBQztRQUNILENBQUM7UUFDRCxPQUFPLEVBQUUsSUFBSSxFQUFFLGdCQUFnQixFQUFFLE9BQU8sRUFBRSxnREFBZ0QsRUFBRSxJQUFJLEVBQUUsa0JBQWtCLEVBQUUsQ0FBQztJQUN6SCxDQUFDLENBQUM7QUFDSixDQUFDIn0=
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type * as plugins from './plugins.js';
|
|
2
|
+
import type { IFlexHarnessChatCaller, IFlexHarnessChatLimits } from './interfaces.js';
|
|
3
|
+
export declare const BAD_REQUEST_MESSAGE = "The request is malformed. Reload the page and try again.";
|
|
4
|
+
export declare const STOPPED_MESSAGE = "The assistant has stopped. Reload the page and try again.";
|
|
5
|
+
/** One key per tab and scope: the same tab id in two scopes names two tabs. */
|
|
6
|
+
export declare const tabKey: (tabArg: IFlexHarnessChatCaller) => string;
|
|
7
|
+
export declare const isSameTab: (leftArg: IFlexHarnessChatCaller, rightArg: IFlexHarnessChatCaller) => boolean;
|
|
8
|
+
/** A subscription id: 16 random bytes in hex, chosen by the tab. */
|
|
9
|
+
export declare const readRandomId: (valueArg: unknown) => string;
|
|
10
|
+
export declare const readSessionId: (valueArg: unknown, notFoundMessageArg: string) => string;
|
|
11
|
+
export declare const readTitle: (valueArg: unknown, limitsArg: IFlexHarnessChatLimits) => string;
|
|
12
|
+
/** A conversation title from its first message: the first line, shortened. */
|
|
13
|
+
export declare const titleFromMessage: (sendArg: plugins.IHarnessComposerSendDetail) => string;
|
|
14
|
+
/**
|
|
15
|
+
* The parts of a composer message the hub uses, checked. The composer's model, account and effort
|
|
16
|
+
* choices are not among them: the host's model resolver decides, from the turn's context.
|
|
17
|
+
*/
|
|
18
|
+
export declare const readSendDetail: (valueArg: unknown, limitsArg: IFlexHarnessChatLimits) => plugins.IHarnessComposerSendDetail;
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { FlexHarnessChatRequestError } from './errors.js';
|
|
2
|
+
export const BAD_REQUEST_MESSAGE = 'The request is malformed. Reload the page and try again.';
|
|
3
|
+
export const STOPPED_MESSAGE = 'The assistant has stopped. Reload the page and try again.';
|
|
4
|
+
const RANDOM_ID_PATTERN = /^[0-9a-f]{32}$/;
|
|
5
|
+
const MAX_SESSION_ID_CHARS = 256;
|
|
6
|
+
const TITLE_MAX_CHARS = 80;
|
|
7
|
+
const ATTACHMENT_KINDS = ['image', 'text', 'binary'];
|
|
8
|
+
/** One key per tab and scope: the same tab id in two scopes names two tabs. */
|
|
9
|
+
export const tabKey = (tabArg) => `${tabArg.scopeId}\n${tabArg.tabId}`;
|
|
10
|
+
export const isSameTab = (leftArg, rightArg) => leftArg.tabId === rightArg.tabId && leftArg.scopeId === rightArg.scopeId;
|
|
11
|
+
const badRequest = () => new FlexHarnessChatRequestError(BAD_REQUEST_MESSAGE);
|
|
12
|
+
const isRecord = (valueArg) => !!valueArg && typeof valueArg === 'object' && !Array.isArray(valueArg);
|
|
13
|
+
/** A subscription id: 16 random bytes in hex, chosen by the tab. */
|
|
14
|
+
export const readRandomId = (valueArg) => {
|
|
15
|
+
if (typeof valueArg !== 'string' || !RANDOM_ID_PATTERN.test(valueArg))
|
|
16
|
+
throw badRequest();
|
|
17
|
+
return valueArg;
|
|
18
|
+
};
|
|
19
|
+
export const readSessionId = (valueArg, notFoundMessageArg) => {
|
|
20
|
+
if (typeof valueArg !== 'string' || !valueArg || valueArg.length > MAX_SESSION_ID_CHARS) {
|
|
21
|
+
throw new FlexHarnessChatRequestError(notFoundMessageArg);
|
|
22
|
+
}
|
|
23
|
+
return valueArg;
|
|
24
|
+
};
|
|
25
|
+
export const readTitle = (valueArg, limitsArg) => {
|
|
26
|
+
const title = typeof valueArg === 'string' ? valueArg.trim() : '';
|
|
27
|
+
if (!title || title.length > limitsArg.maxTitleChars) {
|
|
28
|
+
throw new FlexHarnessChatRequestError(`A title has 1 to ${limitsArg.maxTitleChars} characters.`);
|
|
29
|
+
}
|
|
30
|
+
return title;
|
|
31
|
+
};
|
|
32
|
+
/** A conversation title from its first message: the first line, shortened. */
|
|
33
|
+
export const titleFromMessage = (sendArg) => {
|
|
34
|
+
const text = sendArg.text || sendArg.attachments.map((attachment) => attachment.name).join(', ');
|
|
35
|
+
const line = text.split('\n').map((part) => part.trim()).find((part) => !!part) || 'New conversation';
|
|
36
|
+
return line.length > TITLE_MAX_CHARS ? line.slice(0, TITLE_MAX_CHARS - 1).trimEnd() + '…' : line;
|
|
37
|
+
};
|
|
38
|
+
const readOptionalString = (valueArg, maxCharsArg) => {
|
|
39
|
+
if (valueArg === undefined)
|
|
40
|
+
return undefined;
|
|
41
|
+
if (typeof valueArg !== 'string' || valueArg.length > maxCharsArg)
|
|
42
|
+
throw badRequest();
|
|
43
|
+
return valueArg;
|
|
44
|
+
};
|
|
45
|
+
const readAttachment = (valueArg, limitsArg) => {
|
|
46
|
+
if (!isRecord(valueArg)
|
|
47
|
+
|| typeof valueArg.id !== 'string'
|
|
48
|
+
|| typeof valueArg.name !== 'string'
|
|
49
|
+
|| typeof valueArg.mediaType !== 'string'
|
|
50
|
+
|| typeof valueArg.size !== 'number'
|
|
51
|
+
|| typeof valueArg.kind !== 'string'
|
|
52
|
+
|| !ATTACHMENT_KINDS.includes(valueArg.kind)) {
|
|
53
|
+
throw badRequest();
|
|
54
|
+
}
|
|
55
|
+
const text = readOptionalString(valueArg.text, limitsArg.maxAttachmentChars);
|
|
56
|
+
const dataBase64 = readOptionalString(valueArg.dataBase64, limitsArg.maxAttachmentChars);
|
|
57
|
+
return {
|
|
58
|
+
id: valueArg.id.slice(0, 128),
|
|
59
|
+
name: valueArg.name.slice(0, 255),
|
|
60
|
+
mediaType: valueArg.mediaType.slice(0, 255),
|
|
61
|
+
size: valueArg.size,
|
|
62
|
+
kind: valueArg.kind,
|
|
63
|
+
...(text === undefined ? {} : { text }),
|
|
64
|
+
...(dataBase64 === undefined ? {} : { dataBase64 }),
|
|
65
|
+
...(valueArg.truncated === true ? { truncated: true } : {}),
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
/**
|
|
69
|
+
* The parts of a composer message the hub uses, checked. The composer's model, account and effort
|
|
70
|
+
* choices are not among them: the host's model resolver decides, from the turn's context.
|
|
71
|
+
*/
|
|
72
|
+
export const readSendDetail = (valueArg, limitsArg) => {
|
|
73
|
+
if (!isRecord(valueArg) || typeof valueArg.text !== 'string' || valueArg.text.length > limitsArg.maxMessageChars) {
|
|
74
|
+
throw badRequest();
|
|
75
|
+
}
|
|
76
|
+
if (!Array.isArray(valueArg.attachments) || valueArg.attachments.length > limitsArg.maxAttachments) {
|
|
77
|
+
throw badRequest();
|
|
78
|
+
}
|
|
79
|
+
const attachments = valueArg.attachments.map((entry) => readAttachment(entry, limitsArg));
|
|
80
|
+
const chars = attachments.reduce((sum, attachment) => sum + (attachment.text?.length ?? 0) + (attachment.dataBase64?.length ?? 0), 0);
|
|
81
|
+
if (chars > limitsArg.maxAttachmentChars)
|
|
82
|
+
throw new FlexHarnessChatRequestError('The attachments are too large.');
|
|
83
|
+
if (!valueArg.text.trim() && attachments.length === 0)
|
|
84
|
+
throw new FlexHarnessChatRequestError('The message is empty.');
|
|
85
|
+
// a message sent while a turn runs steers it, whatever delivery the composer chose
|
|
86
|
+
return { delivery: 'turn', text: valueArg.text, attachments };
|
|
87
|
+
};
|
|
88
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZnVuY3Rpb25zLnZhbGlkYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19jaGF0X2hhcm5lc3Nfc2VydmVyL2Z1bmN0aW9ucy52YWxpZGF0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUNBLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUcxRCxNQUFNLENBQUMsTUFBTSxtQkFBbUIsR0FBRywwREFBMEQsQ0FBQztBQUM5RixNQUFNLENBQUMsTUFBTSxlQUFlLEdBQUcsMkRBQTJELENBQUM7QUFDM0YsTUFBTSxpQkFBaUIsR0FBRyxnQkFBZ0IsQ0FBQztBQUMzQyxNQUFNLG9CQUFvQixHQUFHLEdBQUcsQ0FBQztBQUNqQyxNQUFNLGVBQWUsR0FBRyxFQUFFLENBQUM7QUFDM0IsTUFBTSxnQkFBZ0IsR0FBc0IsQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLFFBQVEsQ0FBQyxDQUFDO0FBRXhFLCtFQUErRTtBQUMvRSxNQUFNLENBQUMsTUFBTSxNQUFNLEdBQUcsQ0FBQyxNQUE4QixFQUFVLEVBQUUsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxPQUFPLEtBQUssTUFBTSxDQUFDLEtBQUssRUFBRSxDQUFDO0FBRXZHLE1BQU0sQ0FBQyxNQUFNLFNBQVMsR0FBRyxDQUFDLE9BQStCLEVBQUUsUUFBZ0MsRUFBVyxFQUFFLENBQ3RHLE9BQU8sQ0FBQyxLQUFLLEtBQUssUUFBUSxDQUFDLEtBQUssSUFBSSxPQUFPLENBQUMsT0FBTyxLQUFLLFFBQVEsQ0FBQyxPQUFPLENBQUM7QUFFM0UsTUFBTSxVQUFVLEdBQUcsR0FBRyxFQUFFLENBQUMsSUFBSSwyQkFBMkIsQ0FBQyxtQkFBbUIsQ0FBQyxDQUFDO0FBRTlFLE1BQU0sUUFBUSxHQUFHLENBQUMsUUFBaUIsRUFBdUMsRUFBRSxDQUMxRSxDQUFDLENBQUMsUUFBUSxJQUFJLE9BQU8sUUFBUSxLQUFLLFFBQVEsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMs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
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { FlexHarnessChatHub, defaultFlexHarnessChatLimits, flexHarnessChatSessionMeta, } from './classes.chathub.js';
|
|
2
|
+
export { FlexHarnessChatRequestError, FlexHarnessChatTabUnavailableError } from './errors.js';
|
|
3
|
+
export { createFlexHarnessChatErrorProjector, type IFlexHarnessChatErrorProjectorOptions, } from './functions.errorprojector.js';
|
|
4
|
+
export type { IFlexHarnessChatCaller, IFlexHarnessChatHubOptions, IFlexHarnessChatLimits, IFlexHarnessChatPeer, IFlexHarnessChatPeers, IFlexHarnessChatTurn, TFlexHarnessChatHubHarness, } from './interfaces.js';
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
export { FlexHarnessChatHub, defaultFlexHarnessChatLimits, flexHarnessChatSessionMeta, } from './classes.chathub.js';
|
|
2
|
+
export { FlexHarnessChatRequestError, FlexHarnessChatTabUnavailableError } from './errors.js';
|
|
3
|
+
export { createFlexHarnessChatErrorProjector, } from './functions.errorprojector.js';
|
|
4
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi90c19jaGF0X2hhcm5lc3Nfc2VydmVyL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFDTCxrQkFBa0IsRUFDbEIsNEJBQTRCLEVBQzVCLDBCQUEwQixHQUMzQixNQUFNLHNCQUFzQixDQUFDO0FBQzlCLE9BQU8sRUFBRSwyQkFBMkIsRUFBRSxrQ0FBa0MsRUFBRSxNQUFNLGFBQWEsQ0FBQztBQUM5RixPQUFPLEVBQ0wsbUNBQW1DLEdBRXBDLE1BQU0sK0JBQStCLENBQUMifQ==
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import type * as plugins from './plugins.js';
|
|
2
|
+
/**
|
|
3
|
+
* Who a request is from, as the host established it: the tab, and the scope whose conversations it
|
|
4
|
+
* may reach. A tab is named by both: the same tab id in two scopes names two tabs.
|
|
5
|
+
*/
|
|
6
|
+
export interface IFlexHarnessChatCaller {
|
|
7
|
+
/** the browser tab, a per-page secret; pushes and tool calls of its turns go to it */
|
|
8
|
+
tabId: string;
|
|
9
|
+
/** derived by the host from its own authentication, never taken from the browser */
|
|
10
|
+
scopeId: string;
|
|
11
|
+
}
|
|
12
|
+
/** One tab, reached over its current connection. */
|
|
13
|
+
export interface IFlexHarnessChatPeer {
|
|
14
|
+
update(push: plugins.IFlexHarnessChatUpdate): Promise<void>;
|
|
15
|
+
sessions(push: plugins.IFlexHarnessChatSessionsPush): Promise<void>;
|
|
16
|
+
runTool(request: plugins.IFlexHarnessChatToolRequest, options: {
|
|
17
|
+
timeoutMs: number;
|
|
18
|
+
abortSignal?: AbortSignal;
|
|
19
|
+
}): Promise<plugins.TJsonValue>;
|
|
20
|
+
}
|
|
21
|
+
/** Where the hub finds the tabs it talks to. */
|
|
22
|
+
export interface IFlexHarnessChatPeers {
|
|
23
|
+
/** The tab's current connection in its scope, or null when the tab is gone. */
|
|
24
|
+
find(tab: IFlexHarnessChatCaller): Promise<IFlexHarnessChatPeer | null>;
|
|
25
|
+
}
|
|
26
|
+
/** The running turn of a conversation: the tab that started it and the context it was sent with. */
|
|
27
|
+
export interface IFlexHarnessChatTurn<TContext> {
|
|
28
|
+
readonly scopeId: string;
|
|
29
|
+
readonly sessionId: string;
|
|
30
|
+
readonly tabId: string;
|
|
31
|
+
readonly context: TContext;
|
|
32
|
+
}
|
|
33
|
+
export interface IFlexHarnessChatLimits {
|
|
34
|
+
/** A turn that runs longer is stopped. Default: 10 minutes. */
|
|
35
|
+
turnTimeoutMs: number;
|
|
36
|
+
/** How long a message may wait for a turn that is already ending. Default: 30 seconds. */
|
|
37
|
+
admissionWaitMs: number;
|
|
38
|
+
/** A tool call of the tab that is not answered in time fails. Default: 2 minutes. */
|
|
39
|
+
toolTimeoutMs: number;
|
|
40
|
+
/** Deltas one update may carry; a tab further behind gets the changed rows. Default: 2000. */
|
|
41
|
+
maxPendingDeltas: number;
|
|
42
|
+
/** Characters of a message's text. Default: 100 000. */
|
|
43
|
+
maxMessageChars: number;
|
|
44
|
+
/** Attachments of one message. Default: 16. */
|
|
45
|
+
maxAttachments: number;
|
|
46
|
+
/** Characters of all attachment payloads of one message, as sent. Default: 8 MiB. */
|
|
47
|
+
maxAttachmentChars: number;
|
|
48
|
+
/** Characters of a conversation title. Default: 200. */
|
|
49
|
+
maxTitleChars: number;
|
|
50
|
+
/** How often tabs that are gone are forgotten. Default: 5 minutes. */
|
|
51
|
+
sweepIntervalMs: number;
|
|
52
|
+
}
|
|
53
|
+
/** The harness calls a hub makes; a `FlexHarness` of any scope provides them. */
|
|
54
|
+
export type TFlexHarnessChatHubHarness = Pick<plugins.FlexHarness<unknown>, 'subscribe' | 'listSessions' | 'createSession' | 'getSession' | 'updateSession' | 'deleteSession' | 'getSessionView' | 'getSessionReversionInfo' | 'enqueuePrompt' | 'steerPrompt' | 'getPromptQueueEntry' | 'abort' | 'cancelPrompt' | 'respondToPermission' | 'undoSession' | 'redoSession'>;
|
|
55
|
+
export interface IFlexHarnessChatHubOptions<TContext> {
|
|
56
|
+
/**
|
|
57
|
+
* The harness the conversations run on. The host keeps configuring it: its model resolver and
|
|
58
|
+
* tool provider read the running turn with `hub.turnOf()`.
|
|
59
|
+
*/
|
|
60
|
+
harness: TFlexHarnessChatHubHarness;
|
|
61
|
+
peers: IFlexHarnessChatPeers;
|
|
62
|
+
/** Checks the context a message is sent with and returns it as the turn carries it; throw to refuse. */
|
|
63
|
+
readContext(value: plugins.TJsonValue): TContext;
|
|
64
|
+
/** The title of a conversation a message starts. Defaults to the message's first line. */
|
|
65
|
+
titleOf?(send: plugins.IHarnessComposerSendDetail): string;
|
|
66
|
+
limits?: Partial<IFlexHarnessChatLimits>;
|
|
67
|
+
}
|