@krischoichoi/channel-harness 0.6.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/README.md +110 -0
- package/lib/access/controller.d.ts +37 -0
- package/lib/access/controller.d.ts.map +1 -0
- package/lib/access/controller.js +51 -0
- package/lib/access/controller.js.map +1 -0
- package/lib/access/decision.d.ts +18 -0
- package/lib/access/decision.d.ts.map +1 -0
- package/lib/access/decision.js +2 -0
- package/lib/access/decision.js.map +1 -0
- package/lib/access/resolver.d.ts +41 -0
- package/lib/access/resolver.d.ts.map +1 -0
- package/lib/access/resolver.js +31 -0
- package/lib/access/resolver.js.map +1 -0
- package/lib/agent-manager.d.ts +314 -0
- package/lib/agent-manager.d.ts.map +1 -0
- package/lib/agent-manager.js +603 -0
- package/lib/agent-manager.js.map +1 -0
- package/lib/agent-router.d.ts +37 -0
- package/lib/agent-router.d.ts.map +1 -0
- package/lib/agent-router.js +33 -0
- package/lib/agent-router.js.map +1 -0
- package/lib/bind-support.d.ts +23 -0
- package/lib/bind-support.d.ts.map +1 -0
- package/lib/bind-support.js +63 -0
- package/lib/bind-support.js.map +1 -0
- package/lib/binding-store.d.ts +104 -0
- package/lib/binding-store.d.ts.map +1 -0
- package/lib/binding-store.js +354 -0
- package/lib/binding-store.js.map +1 -0
- package/lib/bridge.d.ts +248 -0
- package/lib/bridge.d.ts.map +1 -0
- package/lib/bridge.js +961 -0
- package/lib/bridge.js.map +1 -0
- package/lib/channel-label.d.ts +46 -0
- package/lib/channel-label.d.ts.map +1 -0
- package/lib/channel-label.js +89 -0
- package/lib/channel-label.js.map +1 -0
- package/lib/channel-session-factory.d.ts +76 -0
- package/lib/channel-session-factory.d.ts.map +1 -0
- package/lib/channel-session-factory.js +187 -0
- package/lib/channel-session-factory.js.map +1 -0
- package/lib/commands/bind.d.ts +21 -0
- package/lib/commands/bind.d.ts.map +1 -0
- package/lib/commands/bind.js +91 -0
- package/lib/commands/bind.js.map +1 -0
- package/lib/commands/help.d.ts +15 -0
- package/lib/commands/help.d.ts.map +1 -0
- package/lib/commands/help.js +89 -0
- package/lib/commands/help.js.map +1 -0
- package/lib/commands/index.d.ts +122 -0
- package/lib/commands/index.d.ts.map +1 -0
- package/lib/commands/index.js +63 -0
- package/lib/commands/index.js.map +1 -0
- package/lib/commands/locale.d.ts +9 -0
- package/lib/commands/locale.d.ts.map +1 -0
- package/lib/commands/locale.js +27 -0
- package/lib/commands/locale.js.map +1 -0
- package/lib/commands/mirror.d.ts +14 -0
- package/lib/commands/mirror.d.ts.map +1 -0
- package/lib/commands/mirror.js +44 -0
- package/lib/commands/mirror.js.map +1 -0
- package/lib/commands/model.d.ts +20 -0
- package/lib/commands/model.d.ts.map +1 -0
- package/lib/commands/model.js +106 -0
- package/lib/commands/model.js.map +1 -0
- package/lib/commands/models.d.ts +14 -0
- package/lib/commands/models.d.ts.map +1 -0
- package/lib/commands/models.js +67 -0
- package/lib/commands/models.js.map +1 -0
- package/lib/commands/new.d.ts +14 -0
- package/lib/commands/new.d.ts.map +1 -0
- package/lib/commands/new.js +37 -0
- package/lib/commands/new.js.map +1 -0
- package/lib/commands/status.d.ts +12 -0
- package/lib/commands/status.d.ts.map +1 -0
- package/lib/commands/status.js +30 -0
- package/lib/commands/status.js.map +1 -0
- package/lib/commands/stop.d.ts +16 -0
- package/lib/commands/stop.d.ts.map +1 -0
- package/lib/commands/stop.js +27 -0
- package/lib/commands/stop.js.map +1 -0
- package/lib/commands/version.d.ts +25 -0
- package/lib/commands/version.d.ts.map +1 -0
- package/lib/commands/version.js +57 -0
- package/lib/commands/version.js.map +1 -0
- package/lib/config.d.ts +119 -0
- package/lib/config.d.ts.map +1 -0
- package/lib/config.js +60 -0
- package/lib/config.js.map +1 -0
- package/lib/debug-logger.d.ts +8 -0
- package/lib/debug-logger.d.ts.map +1 -0
- package/lib/debug-logger.js +32 -0
- package/lib/debug-logger.js.map +1 -0
- package/lib/dsh-home.d.ts +12 -0
- package/lib/dsh-home.d.ts.map +1 -0
- package/lib/dsh-home.js +31 -0
- package/lib/dsh-home.js.map +1 -0
- package/lib/failure-display.d.ts +10 -0
- package/lib/failure-display.d.ts.map +1 -0
- package/lib/failure-display.js +42 -0
- package/lib/failure-display.js.map +1 -0
- package/lib/file-provider.d.ts +96 -0
- package/lib/file-provider.d.ts.map +1 -0
- package/lib/file-provider.js +44 -0
- package/lib/file-provider.js.map +1 -0
- package/lib/index.d.ts +31 -0
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +31 -0
- package/lib/index.js.map +1 -0
- package/lib/interactions/index.d.ts +13 -0
- package/lib/interactions/index.d.ts.map +1 -0
- package/lib/interactions/index.js +13 -0
- package/lib/interactions/index.js.map +1 -0
- package/lib/interactions/question-backend.d.ts +133 -0
- package/lib/interactions/question-backend.d.ts.map +1 -0
- package/lib/interactions/question-backend.js +37 -0
- package/lib/interactions/question-backend.js.map +1 -0
- package/lib/interactions/question-presenter.d.ts +68 -0
- package/lib/interactions/question-presenter.d.ts.map +1 -0
- package/lib/interactions/question-presenter.js +425 -0
- package/lib/interactions/question-presenter.js.map +1 -0
- package/lib/interactions/question-renderer.d.ts +37 -0
- package/lib/interactions/question-renderer.d.ts.map +1 -0
- package/lib/interactions/question-renderer.js +79 -0
- package/lib/interactions/question-renderer.js.map +1 -0
- package/lib/interactions/question-state.d.ts +106 -0
- package/lib/interactions/question-state.d.ts.map +1 -0
- package/lib/interactions/question-state.js +99 -0
- package/lib/interactions/question-state.js.map +1 -0
- package/lib/interactions/question-text-answer.d.ts +37 -0
- package/lib/interactions/question-text-answer.d.ts.map +1 -0
- package/lib/interactions/question-text-answer.js +70 -0
- package/lib/interactions/question-text-answer.js.map +1 -0
- package/lib/interactions/question-waterfall-backend.d.ts +42 -0
- package/lib/interactions/question-waterfall-backend.d.ts.map +1 -0
- package/lib/interactions/question-waterfall-backend.js +162 -0
- package/lib/interactions/question-waterfall-backend.js.map +1 -0
- package/lib/lifecycle.d.ts +36 -0
- package/lib/lifecycle.d.ts.map +1 -0
- package/lib/lifecycle.js +303 -0
- package/lib/lifecycle.js.map +1 -0
- package/lib/loggable-error.d.ts +10 -0
- package/lib/loggable-error.d.ts.map +1 -0
- package/lib/loggable-error.js +32 -0
- package/lib/loggable-error.js.map +1 -0
- package/lib/message-converter.d.ts +64 -0
- package/lib/message-converter.d.ts.map +1 -0
- package/lib/message-converter.js +191 -0
- package/lib/message-converter.js.map +1 -0
- package/lib/model-selection.d.ts +54 -0
- package/lib/model-selection.d.ts.map +1 -0
- package/lib/model-selection.js +116 -0
- package/lib/model-selection.js.map +1 -0
- package/lib/outbox/binding-resolver.d.ts +23 -0
- package/lib/outbox/binding-resolver.d.ts.map +1 -0
- package/lib/outbox/binding-resolver.js +38 -0
- package/lib/outbox/binding-resolver.js.map +1 -0
- package/lib/outbox/capabilities.d.ts +48 -0
- package/lib/outbox/capabilities.d.ts.map +1 -0
- package/lib/outbox/capabilities.js +35 -0
- package/lib/outbox/capabilities.js.map +1 -0
- package/lib/outbox/index.d.ts +14 -0
- package/lib/outbox/index.d.ts.map +1 -0
- package/lib/outbox/index.js +14 -0
- package/lib/outbox/index.js.map +1 -0
- package/lib/outbox/service.d.ts +48 -0
- package/lib/outbox/service.d.ts.map +1 -0
- package/lib/outbox/service.js +74 -0
- package/lib/outbox/service.js.map +1 -0
- package/lib/outbox/target.d.ts +17 -0
- package/lib/outbox/target.d.ts.map +1 -0
- package/lib/outbox/target.js +15 -0
- package/lib/outbox/target.js.map +1 -0
- package/lib/outbox/tool-send.d.ts +19 -0
- package/lib/outbox/tool-send.d.ts.map +1 -0
- package/lib/outbox/tool-send.js +77 -0
- package/lib/outbox/tool-send.js.map +1 -0
- package/lib/outbox/types.d.ts +42 -0
- package/lib/outbox/types.d.ts.map +1 -0
- package/lib/outbox/types.js +30 -0
- package/lib/outbox/types.js.map +1 -0
- package/lib/plugin.d.ts +27 -0
- package/lib/plugin.d.ts.map +1 -0
- package/lib/plugin.js +47 -0
- package/lib/plugin.js.map +1 -0
- package/lib/reply-context-store.d.ts +69 -0
- package/lib/reply-context-store.d.ts.map +1 -0
- package/lib/reply-context-store.js +75 -0
- package/lib/reply-context-store.js.map +1 -0
- package/lib/reply-router.d.ts +138 -0
- package/lib/reply-router.d.ts.map +1 -0
- package/lib/reply-router.js +674 -0
- package/lib/reply-router.js.map +1 -0
- package/lib/session-router.d.ts +49 -0
- package/lib/session-router.d.ts.map +1 -0
- package/lib/session-router.js +45 -0
- package/lib/session-router.js.map +1 -0
- package/lib/workspace-resolver.d.ts +67 -0
- package/lib/workspace-resolver.d.ts.map +1 -0
- package/lib/workspace-resolver.js +102 -0
- package/lib/workspace-resolver.js.map +1 -0
- package/package.json +103 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
2
|
+
import type { StoredBinaryPart } from './message-converter.js';
|
|
3
|
+
export interface ChannelAttachmentContext {
|
|
4
|
+
sessionId: string;
|
|
5
|
+
channelId: string;
|
|
6
|
+
accountId: string;
|
|
7
|
+
conversationId: string;
|
|
8
|
+
conversationType?: 'dm' | 'group';
|
|
9
|
+
threadId?: string;
|
|
10
|
+
messageId: string;
|
|
11
|
+
}
|
|
12
|
+
export interface ChannelAttachmentDescriptor {
|
|
13
|
+
attachmentId: string;
|
|
14
|
+
name: string;
|
|
15
|
+
mimeType?: string;
|
|
16
|
+
bytes: number;
|
|
17
|
+
durable: boolean;
|
|
18
|
+
readable: boolean;
|
|
19
|
+
}
|
|
20
|
+
export type ResolvedChannelAttachmentKind = 'image' | 'file' | 'audio' | 'video';
|
|
21
|
+
export interface ResolvedChannelAttachment {
|
|
22
|
+
kind: ResolvedChannelAttachmentKind;
|
|
23
|
+
data: Uint8Array;
|
|
24
|
+
name: string;
|
|
25
|
+
mimeType?: string;
|
|
26
|
+
}
|
|
27
|
+
/** Input for mirroring one inbound image into the private asset store. */
|
|
28
|
+
export interface ChannelImageStoreInput {
|
|
29
|
+
/**
|
|
30
|
+
* The HARNESS attachment id (the model-visible `sha256:…` ref id) — the
|
|
31
|
+
* mirror MUST be stored under exactly this id so the outbox can resolve
|
|
32
|
+
* the image for outbound sends (issue #7).
|
|
33
|
+
*/
|
|
34
|
+
attachmentId: string;
|
|
35
|
+
data: Uint8Array;
|
|
36
|
+
mimeType?: string;
|
|
37
|
+
name?: string;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Optional generic-attachment capability supplied by an extension package.
|
|
41
|
+
* Core responsibility: `store` / `resolveAttachment` / session ACL.
|
|
42
|
+
* Tool registration (`read_channel_attachment`) is NOT part of the core
|
|
43
|
+
* contract — `installCompatibilityTools` is optional and keeps the tool
|
|
44
|
+
* registered while it is the compatibility path; once Harness
|
|
45
|
+
* ships a native generic-attachment surface this method can be dropped.
|
|
46
|
+
*/
|
|
47
|
+
export interface ChannelAttachmentProvider {
|
|
48
|
+
store(context: ChannelAttachmentContext, part: StoredBinaryPart): Promise<ChannelAttachmentDescriptor | undefined>;
|
|
49
|
+
resolveAttachment(attachmentId: string, sessionId: string): Promise<ResolvedChannelAttachment>;
|
|
50
|
+
/**
|
|
51
|
+
* Optional image mirror (issue #7): store the inbound image bytes under
|
|
52
|
+
* the harness attachment id so `send_channel_message` can re-send them.
|
|
53
|
+
* Best-effort by contract — absent or failing implementations leave the
|
|
54
|
+
* harness image seam authoritative; the outbound resolution then simply
|
|
55
|
+
* misses for images.
|
|
56
|
+
*/
|
|
57
|
+
storeImage?(context: ChannelAttachmentContext, image: ChannelImageStoreInput): Promise<ChannelAttachmentDescriptor | undefined>;
|
|
58
|
+
installCompatibilityTools?(agentContext: Context): Promise<void>;
|
|
59
|
+
/**
|
|
60
|
+
* @deprecated implement {@link installCompatibilityTools} instead. Retained
|
|
61
|
+
* for one compatibility cycle so providers built against the former
|
|
62
|
+
* ChannelFileProvider contract keep registering their agent-scoped tools.
|
|
63
|
+
*/
|
|
64
|
+
installTools?(agentContext: Context): Promise<void>;
|
|
65
|
+
}
|
|
66
|
+
/** @internal Install at most one provider tool hook, preferring the new name. */
|
|
67
|
+
export declare function installAttachmentCompatibilityTools(provider: ChannelAttachmentProvider, agentContext: Context): Promise<void>;
|
|
68
|
+
/**
|
|
69
|
+
* Live view over the OPTIONAL attachment-provider seam.
|
|
70
|
+
*
|
|
71
|
+
* The provider is resolved through `resolve()` on EVERY call instead of being
|
|
72
|
+
* captured once at bridge startup. The bundle's `channels-files` row starts
|
|
73
|
+
* CONCURRENTLY with `channels-harness` (the Cordis entry group creates every
|
|
74
|
+
* row through `Promise.allSettled`), so a startup snapshot is a race: the
|
|
75
|
+
* harness fiber can apply first and permanently wire itself to “no provider”
|
|
76
|
+
* while `channelFiles` mounts a moment later — which silently disables the
|
|
77
|
+
* outbound attachment resolver (issue #7) and the inbound image mirror.
|
|
78
|
+
*
|
|
79
|
+
* Resolving live also keeps the documented contract of the extension honest:
|
|
80
|
+
* deleting the `channels-files` row stays a supported configuration (absent
|
|
81
|
+
* stays absent, nothing becomes a hard dependency).
|
|
82
|
+
*/
|
|
83
|
+
export declare function liveAttachmentProvider(resolve: () => ChannelAttachmentProvider | undefined): ChannelAttachmentProvider;
|
|
84
|
+
/**
|
|
85
|
+
* @deprecated use {@link ChannelAttachmentProvider}
|
|
86
|
+
*/
|
|
87
|
+
export type ChannelFileProvider = ChannelAttachmentProvider;
|
|
88
|
+
/**
|
|
89
|
+
* @deprecated use {@link ChannelAttachmentContext}
|
|
90
|
+
*/
|
|
91
|
+
export type ChannelFileContext = ChannelAttachmentContext;
|
|
92
|
+
/**
|
|
93
|
+
* @deprecated use {@link ChannelAttachmentDescriptor}
|
|
94
|
+
*/
|
|
95
|
+
export type ChannelFileDescriptor = ChannelAttachmentDescriptor;
|
|
96
|
+
//# sourceMappingURL=file-provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-provider.d.ts","sourceRoot":"","sources":["../src/file-provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACnD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,wBAAwB,CAAC;AAE/D,MAAM,WAAW,wBAAwB;IACvC,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,gBAAgB,CAAC,EAAE,IAAI,GAAG,OAAO,CAAC;IAClC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,2BAA2B;IAC1C,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,OAAO,EAAE,OAAO,CAAC;IACjB,QAAQ,EAAE,OAAO,CAAC;CACnB;AAED,MAAM,MAAM,6BAA6B,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,OAAO,CAAC;AAEjF,MAAM,WAAW,yBAAyB;IACxC,IAAI,EAAE,6BAA6B,CAAC;IACpC,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,0EAA0E;AAC1E,MAAM,WAAW,sBAAsB;IACrC;;;;OAIG;IACH,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,yBAAyB;IACxC,KAAK,CACH,OAAO,EAAE,wBAAwB,EACjC,IAAI,EAAE,gBAAgB,GACrB,OAAO,CAAC,2BAA2B,GAAG,SAAS,CAAC,CAAC;IACpD,iBAAiB,CACf,YAAY,EAAE,MAAM,EACpB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC,yBAAyB,CAAC,CAAC;IACtC;;;;;;OAMG;IACH,UAAU,CAAC,CACT,OAAO,EAAE,wBAAwB,EACjC,KAAK,EAAE,sBAAsB,GAC5B,OAAO,CAAC,2BAA2B,GAAG,SAAS,CAAC,CAAC;IACpD,yBAAyB,CAAC,CAAC,YAAY,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IACjE;;;;OAIG;IACH,YAAY,CAAC,CAAC,YAAY,EAAE,OAAO,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACrD;AAED,iFAAiF;AACjF,wBAAsB,mCAAmC,CACvD,QAAQ,EAAE,yBAAyB,EACnC,YAAY,EAAE,OAAO,GACpB,OAAO,CAAC,IAAI,CAAC,CAGf;AAED;;;;;;;;;;;;;;GAcG;AACH,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,MAAM,yBAAyB,GAAG,SAAS,GACnD,yBAAyB,CAuB3B;AAED;;GAEG;AACH,MAAM,MAAM,mBAAmB,GAAG,yBAAyB,CAAC;AAE5D;;GAEG;AACH,MAAM,MAAM,kBAAkB,GAAG,wBAAwB,CAAC;AAE1D;;GAEG;AACH,MAAM,MAAM,qBAAqB,GAAG,2BAA2B,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** @internal Install at most one provider tool hook, preferring the new name. */
|
|
2
|
+
export async function installAttachmentCompatibilityTools(provider, agentContext) {
|
|
3
|
+
const install = provider.installCompatibilityTools ?? provider.installTools;
|
|
4
|
+
await install?.call(provider, agentContext);
|
|
5
|
+
}
|
|
6
|
+
/**
|
|
7
|
+
* Live view over the OPTIONAL attachment-provider seam.
|
|
8
|
+
*
|
|
9
|
+
* The provider is resolved through `resolve()` on EVERY call instead of being
|
|
10
|
+
* captured once at bridge startup. The bundle's `channels-files` row starts
|
|
11
|
+
* CONCURRENTLY with `channels-harness` (the Cordis entry group creates every
|
|
12
|
+
* row through `Promise.allSettled`), so a startup snapshot is a race: the
|
|
13
|
+
* harness fiber can apply first and permanently wire itself to “no provider”
|
|
14
|
+
* while `channelFiles` mounts a moment later — which silently disables the
|
|
15
|
+
* outbound attachment resolver (issue #7) and the inbound image mirror.
|
|
16
|
+
*
|
|
17
|
+
* Resolving live also keeps the documented contract of the extension honest:
|
|
18
|
+
* deleting the `channels-files` row stays a supported configuration (absent
|
|
19
|
+
* stays absent, nothing becomes a hard dependency).
|
|
20
|
+
*/
|
|
21
|
+
export function liveAttachmentProvider(resolve) {
|
|
22
|
+
return {
|
|
23
|
+
async store(context, part) {
|
|
24
|
+
return resolve()?.store(context, part);
|
|
25
|
+
},
|
|
26
|
+
async resolveAttachment(attachmentId, sessionId) {
|
|
27
|
+
const provider = resolve();
|
|
28
|
+
if (!provider) {
|
|
29
|
+
throw new Error('no channel attachment provider is mounted (the channelFiles service is unavailable)');
|
|
30
|
+
}
|
|
31
|
+
return provider.resolveAttachment(attachmentId, sessionId);
|
|
32
|
+
},
|
|
33
|
+
async storeImage(context, image) {
|
|
34
|
+
return resolve()?.storeImage?.(context, image);
|
|
35
|
+
},
|
|
36
|
+
async installCompatibilityTools(agentContext) {
|
|
37
|
+
const provider = resolve();
|
|
38
|
+
if (!provider)
|
|
39
|
+
return;
|
|
40
|
+
await installAttachmentCompatibilityTools(provider, agentContext);
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=file-provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"file-provider.js","sourceRoot":"","sources":["../src/file-provider.ts"],"names":[],"mappings":"AAiFA,iFAAiF;AACjF,MAAM,CAAC,KAAK,UAAU,mCAAmC,CACvD,QAAmC,EACnC,YAAqB;IAErB,MAAM,OAAO,GAAG,QAAQ,CAAC,yBAAyB,IAAI,QAAQ,CAAC,YAAY,CAAC;IAC5E,MAAM,OAAO,EAAE,IAAI,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;AAC9C,CAAC;AAED;;;;;;;;;;;;;;GAcG;AACH,MAAM,UAAU,sBAAsB,CACpC,OAAoD;IAEpD,OAAO;QACL,KAAK,CAAC,KAAK,CAAC,OAAO,EAAE,IAAI;YACvB,OAAO,OAAO,EAAE,EAAE,KAAK,CAAC,OAAO,EAAE,IAAI,CAAC,CAAC;QACzC,CAAC;QACD,KAAK,CAAC,iBAAiB,CAAC,YAAY,EAAE,SAAS;YAC7C,MAAM,QAAQ,GAAG,OAAO,EAAE,CAAC;YAC3B,IAAI,CAAC,QAAQ,EAAE,CAAC;gBACd,MAAM,IAAI,KAAK,CACb,qFAAqF,CACtF,CAAC;YACJ,CAAC;YACD,OAAO,QAAQ,CAAC,iBAAiB,CAAC,YAAY,EAAE,SAAS,CAAC,CAAC;QAC7D,CAAC;QACD,KAAK,CAAC,UAAU,CAAC,OAAO,EAAE,KAAK;YAC7B,OAAO,OAAO,EAAE,EAAE,UAAU,EAAE,CAAC,OAAO,EAAE,KAAK,CAAC,CAAC;QACjD,CAAC;QACD,KAAK,CAAC,yBAAyB,CAAC,YAAY;YAC1C,MAAM,QAAQ,GAAG,OAAO,EAAE,CAAC;YAC3B,IAAI,CAAC,QAAQ;gBAAE,OAAO;YACtB,MAAM,mCAAmC,CAAC,QAAQ,EAAE,YAAY,CAAC,CAAC;QACpE,CAAC;KACF,CAAC;AACJ,CAAC"}
|
package/lib/index.d.ts
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @krischoichoi/channel-harness — the only package that imports Harness public APIs.
|
|
3
|
+
*
|
|
4
|
+
* Bridges ChannelEvents (from `@krischoichoi/channel-core` adapters) to Harness
|
|
5
|
+
* sessions: inbound messages resolve to a SessionBinding, resolve/create an
|
|
6
|
+
* agent via `ctx.agents`, and call `agent.followup`; outbound assistant
|
|
7
|
+
* output flows back through the official `session/event` feed to the channel
|
|
8
|
+
* adapter's reply pipeline.
|
|
9
|
+
*
|
|
10
|
+
* This package never imports platform SDKs and never depends on concrete
|
|
11
|
+
* channel packages.
|
|
12
|
+
*/
|
|
13
|
+
export * from './config.js';
|
|
14
|
+
export * from './channel-label.js';
|
|
15
|
+
export * from './dsh-home.js';
|
|
16
|
+
export * from './file-provider.js';
|
|
17
|
+
export * from './outbox/index.js';
|
|
18
|
+
export * from './session-router.js';
|
|
19
|
+
export * from './binding-store.js';
|
|
20
|
+
export * from './agent-router.js';
|
|
21
|
+
export * from './agent-manager.js';
|
|
22
|
+
export * from './message-converter.js';
|
|
23
|
+
export * from './model-selection.js';
|
|
24
|
+
export * from './reply-router.js';
|
|
25
|
+
export * from './reply-context-store.js';
|
|
26
|
+
export * from './interactions/index.js';
|
|
27
|
+
export * from './bridge.js';
|
|
28
|
+
export * from './lifecycle.js';
|
|
29
|
+
export * from './workspace-resolver.js';
|
|
30
|
+
export { name, inject, apply } from './plugin.js';
|
|
31
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC"}
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @krischoichoi/channel-harness — the only package that imports Harness public APIs.
|
|
3
|
+
*
|
|
4
|
+
* Bridges ChannelEvents (from `@krischoichoi/channel-core` adapters) to Harness
|
|
5
|
+
* sessions: inbound messages resolve to a SessionBinding, resolve/create an
|
|
6
|
+
* agent via `ctx.agents`, and call `agent.followup`; outbound assistant
|
|
7
|
+
* output flows back through the official `session/event` feed to the channel
|
|
8
|
+
* adapter's reply pipeline.
|
|
9
|
+
*
|
|
10
|
+
* This package never imports platform SDKs and never depends on concrete
|
|
11
|
+
* channel packages.
|
|
12
|
+
*/
|
|
13
|
+
export * from './config.js';
|
|
14
|
+
export * from './channel-label.js';
|
|
15
|
+
export * from './dsh-home.js';
|
|
16
|
+
export * from './file-provider.js';
|
|
17
|
+
export * from './outbox/index.js';
|
|
18
|
+
export * from './session-router.js';
|
|
19
|
+
export * from './binding-store.js';
|
|
20
|
+
export * from './agent-router.js';
|
|
21
|
+
export * from './agent-manager.js';
|
|
22
|
+
export * from './message-converter.js';
|
|
23
|
+
export * from './model-selection.js';
|
|
24
|
+
export * from './reply-router.js';
|
|
25
|
+
export * from './reply-context-store.js';
|
|
26
|
+
export * from './interactions/index.js';
|
|
27
|
+
export * from './bridge.js';
|
|
28
|
+
export * from './lifecycle.js';
|
|
29
|
+
export * from './workspace-resolver.js';
|
|
30
|
+
export { name, inject, apply } from './plugin.js';
|
|
31
|
+
//# sourceMappingURL=index.js.map
|
package/lib/index.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AACH,cAAc,aAAa,CAAC;AAC5B,cAAc,oBAAoB,CAAC;AACnC,cAAc,eAAe,CAAC;AAC9B,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,qBAAqB,CAAC;AACpC,cAAc,oBAAoB,CAAC;AACnC,cAAc,mBAAmB,CAAC;AAClC,cAAc,oBAAoB,CAAC;AACnC,cAAc,wBAAwB,CAAC;AACvC,cAAc,sBAAsB,CAAC;AACrC,cAAc,mBAAmB,CAAC;AAClC,cAAc,0BAA0B,CAAC;AACzC,cAAc,yBAAyB,CAAC;AACxC,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,yBAAyB,CAAC;AACxC,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,aAAa,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Channel-side human interactions.
|
|
3
|
+
*
|
|
4
|
+
* `QuestionInteraction*` today; the directory and interface naming leave
|
|
5
|
+
* room for an `ApprovalInteraction` sibling (future) without sharing
|
|
6
|
+
* interfaces prematurely — the official question/approval domains compose
|
|
7
|
+
* answerers on the same Cordis waterfall mechanism.
|
|
8
|
+
*/
|
|
9
|
+
export * from './question-backend.js';
|
|
10
|
+
export * from './question-presenter.js';
|
|
11
|
+
export * from './question-state.js';
|
|
12
|
+
export * from './question-waterfall-backend.js';
|
|
13
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/interactions/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iCAAiC,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Channel-side human interactions.
|
|
3
|
+
*
|
|
4
|
+
* `QuestionInteraction*` today; the directory and interface naming leave
|
|
5
|
+
* room for an `ApprovalInteraction` sibling (future) without sharing
|
|
6
|
+
* interfaces prematurely — the official question/approval domains compose
|
|
7
|
+
* answerers on the same Cordis waterfall mechanism.
|
|
8
|
+
*/
|
|
9
|
+
export * from './question-backend.js';
|
|
10
|
+
export * from './question-presenter.js';
|
|
11
|
+
export * from './question-state.js';
|
|
12
|
+
export * from './question-waterfall-backend.js';
|
|
13
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/interactions/index.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,cAAc,uBAAuB,CAAC;AACtC,cAAc,yBAAyB,CAAC;AACxC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iCAAiC,CAAC"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Question interaction backend contract + answerer assembly.
|
|
3
|
+
*
|
|
4
|
+
* The official question domain (`ask_user_question` -> `ctx.userQuestions`)
|
|
5
|
+
* dispatches the `user-questions/request` Cordis waterfall; answerers claim a
|
|
6
|
+
* request by returning an answer or delegate with `next()`. The channel
|
|
7
|
+
* composes ONE waterfall answerer that serves every profile:
|
|
8
|
+
*
|
|
9
|
+
* - **Headless**: the channel is typically the only answerer, so a declined
|
|
10
|
+
* presentation fails the ask (`NO_PROVIDER` from the official service).
|
|
11
|
+
* - **Web profile**: the official Remote/Web answerer is composed on the same
|
|
12
|
+
* waterfall and claims first unless the channel answerer is PREPENDED (see
|
|
13
|
+
* `question-waterfall-backend.ts`); a channel decline still delegates to it.
|
|
14
|
+
*
|
|
15
|
+
* There is no version branching here: the waterfall is the only transport,
|
|
16
|
+
* and the `userQuestions` probe is diagnostic (never an admission gate).
|
|
17
|
+
*
|
|
18
|
+
* Naming leaves room for the upcoming approval interaction:
|
|
19
|
+
* everything here is `QuestionInteraction*` under `interactions/`,
|
|
20
|
+
* and the official domain already carries approval requests a future
|
|
21
|
+
* `ApprovalInteraction` can compose the same way.
|
|
22
|
+
*/
|
|
23
|
+
import type { Context } from '@deepseek-ai/cordis';
|
|
24
|
+
import type { AskUserQuestionAnswer, AskUserQuestionItem } from '@deepseek-ai/dsh-user-questions/types';
|
|
25
|
+
import type { ChannelAdapter, ChannelLogger } from '@krischoichoi/channel-core';
|
|
26
|
+
import type { AgentManager } from '../agent-manager.js';
|
|
27
|
+
import type { ReplyContextStore } from '../reply-context-store.js';
|
|
28
|
+
import { type ChannelUserQuestionService } from './question-waterfall-backend.js';
|
|
29
|
+
import { ChannelQuestionPresenter } from './question-presenter.js';
|
|
30
|
+
/** One question batch arriving from the Harness question domain. */
|
|
31
|
+
export interface QuestionInteractionRequest {
|
|
32
|
+
/** Correlation key the backend minted (the waterfall ask key). */
|
|
33
|
+
key: string;
|
|
34
|
+
sessionId: string;
|
|
35
|
+
/** Official question items; every field (incl. `intent`) is carried verbatim. */
|
|
36
|
+
questions: AskUserQuestionItem[];
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* The channel presentation side, as seen by a backend. Backends push
|
|
40
|
+
* harness-origin question traffic through this sink; the presenter resolves
|
|
41
|
+
* answers back through {@link QuestionInteractionBackend}.
|
|
42
|
+
*/
|
|
43
|
+
export interface QuestionInteractionSink {
|
|
44
|
+
/**
|
|
45
|
+
* Present a question batch on its bound channel conversation.
|
|
46
|
+
*
|
|
47
|
+
* @returns true when the channel took ownership (it will later resolve or
|
|
48
|
+
* cancel through the backend); false when the channel declined (no bound
|
|
49
|
+
* conversation, adapter absent / text unsupported, or a question already
|
|
50
|
+
* pending there) and the backend must delegate the ask to the next
|
|
51
|
+
* answerer.
|
|
52
|
+
*/
|
|
53
|
+
questionRequested(request: QuestionInteractionRequest): Promise<boolean>;
|
|
54
|
+
/**
|
|
55
|
+
* The question settled WITHOUT the channel — the owning tool call aborted.
|
|
56
|
+
* Removes stale channel controls.
|
|
57
|
+
*/
|
|
58
|
+
questionSettledExternally(key: string, state?: 'aborted' | 'externally-settled'): Promise<void>;
|
|
59
|
+
}
|
|
60
|
+
/** A channel-collected answer batch submitted to the Harness question domain. */
|
|
61
|
+
export interface QuestionInteractionResolution {
|
|
62
|
+
key: string;
|
|
63
|
+
sessionId: string;
|
|
64
|
+
answer: AskUserQuestionAnswer;
|
|
65
|
+
}
|
|
66
|
+
/** The channel could not / will not answer a question it had taken. */
|
|
67
|
+
export interface QuestionInteractionCancellation {
|
|
68
|
+
key: string;
|
|
69
|
+
/** Human-readable reason; also the code-carrying message headless. */
|
|
70
|
+
reason: string;
|
|
71
|
+
}
|
|
72
|
+
/** Which official transport a backend speaks. */
|
|
73
|
+
export type QuestionBackendKind = 'waterfall';
|
|
74
|
+
/**
|
|
75
|
+
* Transport-neutral question domain port consumed by the presenter.
|
|
76
|
+
* `QuestionInteraction*` naming keeps room for a future approval sibling
|
|
77
|
+
* without sharing this interface prematurely.
|
|
78
|
+
*/
|
|
79
|
+
export interface QuestionInteractionBackend {
|
|
80
|
+
readonly kind: QuestionBackendKind;
|
|
81
|
+
/** Connect the presenter sink and begin consuming the question domain. */
|
|
82
|
+
start(sink: QuestionInteractionSink): void;
|
|
83
|
+
/** Tear the transport down and settle every still-open question. */
|
|
84
|
+
stop(): Promise<void>;
|
|
85
|
+
/** Submit a complete answer batch (one entry per question, in order). */
|
|
86
|
+
resolve(submission: QuestionInteractionResolution): Promise<void>;
|
|
87
|
+
/** Cancel an open question with a human-readable reason. */
|
|
88
|
+
cancel(cancellation: QuestionInteractionCancellation): Promise<void>;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Live service probes. The waterfall answerer registers on `ctx` and never
|
|
92
|
+
* calls the service, so `getUserQuestions()` is a DIAGNOSTIC probe: it only
|
|
93
|
+
* decides whether the startup miss is logged.
|
|
94
|
+
*/
|
|
95
|
+
export interface QuestionBackendProbe {
|
|
96
|
+
/** The official `ctx.userQuestions` service, when the host spine provides it. */
|
|
97
|
+
getUserQuestions(): ChannelUserQuestionService | undefined;
|
|
98
|
+
/** Root Cordis context the waterfall listener registers on. */
|
|
99
|
+
ctx: Context;
|
|
100
|
+
}
|
|
101
|
+
/** Channel presentation dependencies shared by every backend mode. */
|
|
102
|
+
export interface QuestionInteractionDeps {
|
|
103
|
+
agentManager: AgentManager;
|
|
104
|
+
replyContexts: ReplyContextStore;
|
|
105
|
+
getAdapter(channelId: string): ChannelAdapter | undefined;
|
|
106
|
+
logger: ChannelLogger;
|
|
107
|
+
timeoutMs: number;
|
|
108
|
+
}
|
|
109
|
+
export interface QuestionInteractionOptions extends QuestionInteractionDeps, Omit<QuestionBackendProbe, 'ctx'> {
|
|
110
|
+
ctx: Context;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Backend selection: the waterfall answerer always exists, because it needs
|
|
114
|
+
* only the ROOT context — `ctx.userQuestions` dispatches the event, and this
|
|
115
|
+
* backend never calls the service. The probe is therefore DIAGNOSTIC ONLY.
|
|
116
|
+
*
|
|
117
|
+
* Treating a missing service as fatal (the pre-waterfall behavior) made a
|
|
118
|
+
* transient startup state permanent: profile rows are composed concurrently
|
|
119
|
+
* and `cordis.patch.yml` layers hot-reload, so a `userQuestions` service that
|
|
120
|
+
* mounts after the bridge used to leave channel question presentation
|
|
121
|
+
* disabled for the whole process — every channel-bound ask silently answered
|
|
122
|
+
* by the Web UI instead. A registered listener with no service is inert, so
|
|
123
|
+
* the answerer is composed unconditionally and the miss is only logged.
|
|
124
|
+
*/
|
|
125
|
+
export declare function selectQuestionBackend(probe: Omit<QuestionBackendProbe, 'ctx'> & {
|
|
126
|
+
ctx: Context;
|
|
127
|
+
}, deps: Pick<QuestionInteractionDeps, 'logger'>): QuestionInteractionBackend;
|
|
128
|
+
/**
|
|
129
|
+
* Assemble the whole question interaction stack: probe the service (diagnostic
|
|
130
|
+
* only), build the waterfall backend, and wire the channel presenter on top.
|
|
131
|
+
*/
|
|
132
|
+
export declare function createQuestionInteraction(options: QuestionInteractionOptions): ChannelQuestionPresenter;
|
|
133
|
+
//# sourceMappingURL=question-backend.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"question-backend.d.ts","sourceRoot":"","sources":["../../src/interactions/question-backend.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { WaterfallQuestionBackend } from './question-waterfall-backend.js';
|
|
2
|
+
import { ChannelQuestionPresenter } from './question-presenter.js';
|
|
3
|
+
/**
|
|
4
|
+
* Backend selection: the waterfall answerer always exists, because it needs
|
|
5
|
+
* only the ROOT context — `ctx.userQuestions` dispatches the event, and this
|
|
6
|
+
* backend never calls the service. The probe is therefore DIAGNOSTIC ONLY.
|
|
7
|
+
*
|
|
8
|
+
* Treating a missing service as fatal (the pre-waterfall behavior) made a
|
|
9
|
+
* transient startup state permanent: profile rows are composed concurrently
|
|
10
|
+
* and `cordis.patch.yml` layers hot-reload, so a `userQuestions` service that
|
|
11
|
+
* mounts after the bridge used to leave channel question presentation
|
|
12
|
+
* disabled for the whole process — every channel-bound ask silently answered
|
|
13
|
+
* by the Web UI instead. A registered listener with no service is inert, so
|
|
14
|
+
* the answerer is composed unconditionally and the miss is only logged.
|
|
15
|
+
*/
|
|
16
|
+
export function selectQuestionBackend(probe, deps) {
|
|
17
|
+
if (!probe.getUserQuestions()) {
|
|
18
|
+
deps.logger.warn('[channel-harness] the userQuestions service is not mounted yet; the channel question answerer is registered anyway and claims asks as soon as the service appears');
|
|
19
|
+
}
|
|
20
|
+
return new WaterfallQuestionBackend({ ctx: probe.ctx, logger: deps.logger });
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Assemble the whole question interaction stack: probe the service (diagnostic
|
|
24
|
+
* only), build the waterfall backend, and wire the channel presenter on top.
|
|
25
|
+
*/
|
|
26
|
+
export function createQuestionInteraction(options) {
|
|
27
|
+
const backend = selectQuestionBackend(options, options);
|
|
28
|
+
return new ChannelQuestionPresenter({
|
|
29
|
+
backend,
|
|
30
|
+
agentManager: options.agentManager,
|
|
31
|
+
replyContexts: options.replyContexts,
|
|
32
|
+
getAdapter: options.getAdapter,
|
|
33
|
+
logger: options.logger,
|
|
34
|
+
timeoutMs: options.timeoutMs,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
//# sourceMappingURL=question-backend.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"question-backend.js","sourceRoot":"","sources":["../../src/interactions/question-backend.ts"],"names":[],"mappings":"AA8BA,OAAO,EAAE,wBAAwB,EAAmC,MAAM,iCAAiC,CAAC;AAC5G,OAAO,EAAE,wBAAwB,EAAE,MAAM,yBAAyB,CAAC;AAgGnE;;;;;;;;;;;;GAYG;AACH,MAAM,UAAU,qBAAqB,CACnC,KAA2D,EAC3D,IAA6C;IAE7C,IAAI,CAAC,KAAK,CAAC,gBAAgB,EAAE,EAAE,CAAC;QAC9B,IAAI,CAAC,MAAM,CAAC,IAAI,CACd,mKAAmK,CACpK,CAAC;IACJ,CAAC;IACD,OAAO,IAAI,wBAAwB,CAAC,EAAE,GAAG,EAAE,KAAK,CAAC,GAAG,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC;AAC/E,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,yBAAyB,CACvC,OAAmC;IAEnC,MAAM,OAAO,GAAG,qBAAqB,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;IACxD,OAAO,IAAI,wBAAwB,CAAC;QAClC,OAAO;QACP,YAAY,EAAE,OAAO,CAAC,YAAY;QAClC,aAAa,EAAE,OAAO,CAAC,aAAa;QACpC,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,MAAM,EAAE,OAAO,CAAC,MAAM;QACtB,SAAS,EAAE,OAAO,CAAC,SAAS;KAC7B,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
import type { ChannelAdapter, ChannelEvent, ChannelLogger } from '@krischoichoi/channel-core';
|
|
2
|
+
import type { AgentManager } from '../agent-manager.js';
|
|
3
|
+
import type { ReplyContextStore } from '../reply-context-store.js';
|
|
4
|
+
import type { QuestionInteractionBackend, QuestionInteractionRequest, QuestionInteractionSink } from './question-backend.js';
|
|
5
|
+
export interface ChannelQuestionPresenterOptions {
|
|
6
|
+
backend: QuestionInteractionBackend;
|
|
7
|
+
agentManager: AgentManager;
|
|
8
|
+
replyContexts: ReplyContextStore;
|
|
9
|
+
getAdapter(channelId: string): ChannelAdapter | undefined;
|
|
10
|
+
logger: ChannelLogger;
|
|
11
|
+
timeoutMs: number;
|
|
12
|
+
}
|
|
13
|
+
/**
|
|
14
|
+
* Presents Harness-origin questions (the official `user-questions/request`
|
|
15
|
+
* waterfall) through generic channel actions.
|
|
16
|
+
*/
|
|
17
|
+
export declare class ChannelQuestionPresenter implements QuestionInteractionSink {
|
|
18
|
+
private readonly options;
|
|
19
|
+
private readonly state;
|
|
20
|
+
constructor(options: ChannelQuestionPresenterOptions);
|
|
21
|
+
/** Connect the sink and open the backend transport. */
|
|
22
|
+
start(): void;
|
|
23
|
+
/** Cancel every open question, then tear the backend transport down. */
|
|
24
|
+
stop(): Promise<void>;
|
|
25
|
+
/**
|
|
26
|
+
* Present one question batch on the channel conversation bound to the
|
|
27
|
+
* asking session. Returns false when the channel cannot take ownership
|
|
28
|
+
* (no active reply context, no binding, adapter absent / text unsupported,
|
|
29
|
+
* or another question already pending on that conversation) — the backend
|
|
30
|
+
* decides what a decline means per transport.
|
|
31
|
+
*
|
|
32
|
+
* `interactiveActions` decides only presentation quality, never admission:
|
|
33
|
+
* any `text: true` adapter can answer via numbered plain text; a
|
|
34
|
+
* `interactiveActions: true` adapter upgrades to native buttons.
|
|
35
|
+
*/
|
|
36
|
+
questionRequested(request: QuestionInteractionRequest): Promise<boolean>;
|
|
37
|
+
/** Another client answered, or the owning tool call aborted: drop controls. */
|
|
38
|
+
questionSettledExternally(key: string, state?: 'aborted' | 'externally-settled'): Promise<void>;
|
|
39
|
+
/** Consume an already-authorized channel answer before it reaches the Agent inbox. */
|
|
40
|
+
handleChannelEvent(event: ChannelEvent): Promise<boolean>;
|
|
41
|
+
private present;
|
|
42
|
+
private handleInteraction;
|
|
43
|
+
/**
|
|
44
|
+
* Route one authorized text message into the question flow. DM answers parse
|
|
45
|
+
* directly; group/thread answers must correlate via the platform `replyTo`
|
|
46
|
+
* mapping or the per-question `replyToken` (stripped before parsing).
|
|
47
|
+
* Returns true when the message was consumed by a pending question (never
|
|
48
|
+
* falls through to Agent routing); false otherwise.
|
|
49
|
+
*/
|
|
50
|
+
private handleMessage;
|
|
51
|
+
/**
|
|
52
|
+
* Resolve the answerable text of an inbound message against a pending
|
|
53
|
+
* question. Returns:
|
|
54
|
+
* - the message body for DMs (parse directly), or
|
|
55
|
+
* - the token-stripped body when the platform `replyTo` maps to the prompt,
|
|
56
|
+
* or
|
|
57
|
+
* - the token-stripped body when the reply carries `pending.replyToken`
|
|
58
|
+
* anywhere (`Q-XXXX 2`, `Q-XXXX: 2`, `@bot Q-XXXX 2`), or
|
|
59
|
+
* - `undefined` when nothing correlates (leave for ordinary routing).
|
|
60
|
+
*/
|
|
61
|
+
private correlateMessageBody;
|
|
62
|
+
private advance;
|
|
63
|
+
private submit;
|
|
64
|
+
private cancel;
|
|
65
|
+
private removeButtons;
|
|
66
|
+
private cleanup;
|
|
67
|
+
}
|
|
68
|
+
//# sourceMappingURL=question-presenter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"question-presenter.d.ts","sourceRoot":"","sources":["../../src/interactions/question-presenter.ts"],"names":[],"mappings":"AAuCA,OAAO,KAAK,EACV,cAAc,EACd,YAAY,EACZ,aAAa,EAKd,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AACxD,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AACnE,OAAO,KAAK,EACV,0BAA0B,EAC1B,0BAA0B,EAC1B,uBAAuB,EACxB,MAAM,uBAAuB,CAAC;AAU/B,MAAM,WAAW,+BAA+B;IAC9C,OAAO,EAAE,0BAA0B,CAAC;IACpC,YAAY,EAAE,YAAY,CAAC;IAC3B,aAAa,EAAE,iBAAiB,CAAC;IACjC,UAAU,CAAC,SAAS,EAAE,MAAM,GAAG,cAAc,GAAG,SAAS,CAAC;IAC1D,MAAM,EAAE,aAAa,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;CACnB;AAkBD;;;GAGG;AACH,qBAAa,wBAAyB,YAAW,uBAAuB;IAG1D,OAAO,CAAC,QAAQ,CAAC,OAAO;IAFpC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAA4B;gBAErB,OAAO,EAAE,+BAA+B;IAErE,uDAAuD;IACvD,KAAK,IAAI,IAAI;IAIb,wEAAwE;IAClE,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAW3B;;;;;;;;;;OAUG;IACG,iBAAiB,CAAC,OAAO,EAAE,0BAA0B,GAAG,OAAO,CAAC,OAAO,CAAC;IAuE9E,+EAA+E;IACzE,yBAAyB,CAC7B,GAAG,EAAE,MAAM,EACX,KAAK,GAAE,SAAS,GAAG,oBAA2C,GAC7D,OAAO,CAAC,IAAI,CAAC;IAahB,sFAAsF;IAChF,kBAAkB,CAAC,KAAK,EAAE,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC;YAMjD,OAAO;YAmDP,iBAAiB;IA+C/B;;;;;;OAMG;YACW,aAAa;IAwD3B;;;;;;;;;OASG;IACH,OAAO,CAAC,oBAAoB;YA0Bd,OAAO;YAiBP,MAAM;YAqBN,MAAM;YAeN,aAAa;YAUb,OAAO;CAItB"}
|