@recombine-ai/bosun-lib 0.1.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 (44) hide show
  1. package/README.md +3 -0
  2. package/build/context.d.ts +23 -0
  3. package/build/context.d.ts.map +1 -0
  4. package/build/context.js +41 -0
  5. package/build/context.spec.d.ts +2 -0
  6. package/build/context.spec.d.ts.map +1 -0
  7. package/build/context.spec.js +21 -0
  8. package/build/index.d.ts +7 -0
  9. package/build/index.d.ts.map +1 -0
  10. package/build/index.js +6 -0
  11. package/build/index.test.d.ts +2 -0
  12. package/build/index.test.d.ts.map +1 -0
  13. package/build/interfaces/agent.d.ts +39 -0
  14. package/build/interfaces/agent.d.ts.map +1 -0
  15. package/build/interfaces/agent.js +3 -0
  16. package/build/interfaces/context.d.ts +23 -0
  17. package/build/interfaces/context.d.ts.map +1 -0
  18. package/build/interfaces/dockyard.d.ts +6 -0
  19. package/build/interfaces/dockyard.d.ts.map +1 -0
  20. package/build/interfaces/dockyard.js +1 -0
  21. package/build/interfaces/mock.d.ts +6 -0
  22. package/build/interfaces/mock.d.ts.map +1 -0
  23. package/build/interfaces/other.d.ts +19 -0
  24. package/build/interfaces/other.d.ts.map +1 -0
  25. package/build/interfaces/step-registry.d.ts +16 -0
  26. package/build/interfaces/step-registry.d.ts.map +1 -0
  27. package/build/mock.d.ts +6 -0
  28. package/build/mock.d.ts.map +1 -0
  29. package/build/mock.js +28 -0
  30. package/build/std-mocks/platform.d.ts +8 -0
  31. package/build/std-mocks/platform.d.ts.map +1 -0
  32. package/build/std-mocks/platform.js +37 -0
  33. package/build/std-mocks/rc-voice.d.ts +11 -0
  34. package/build/std-mocks/rc-voice.d.ts.map +1 -0
  35. package/build/std-mocks/rc-voice.js +137 -0
  36. package/build/stubs.d.ts +4 -0
  37. package/build/stubs.d.ts.map +1 -0
  38. package/build/test-agent.d.ts +4 -0
  39. package/build/test-agent.d.ts.map +1 -0
  40. package/build/test-agent.js +70 -0
  41. package/build/utils.d.ts +4 -0
  42. package/build/utils.d.ts.map +1 -0
  43. package/build/utils.js +7 -0
  44. package/package.json +30 -0
package/README.md ADDED
@@ -0,0 +1,3 @@
1
+ # Bosun Lib
2
+
3
+ Bosun conversational agents IDE bindings to agents build on Recombine platform
@@ -0,0 +1,23 @@
1
+ type Ctx = Record<string, any>;
2
+ type Paths<T> = T extends object ? {
3
+ [K in keyof T]: [K] | [K, ...Paths<T[K]>];
4
+ }[keyof T] : never;
5
+ type PathValue<T, P extends any[]> = P extends [infer First, ...infer Rest] ? First extends keyof T ? Rest['length'] extends 0 ? T[First] : PathValue<T[First], Rest> : never : never;
6
+ declare class Context<T extends Ctx> {
7
+ #private;
8
+ constructor(context: T);
9
+ set<P extends Paths<T>>(path: P extends any[] ? P : never, value: PathValue<T, P>): void;
10
+ set(newContext: T): void;
11
+ get(): T;
12
+ swap(newContext: T): void;
13
+ subscribe: (listener: (context: T) => void) => () => boolean;
14
+ setPromptContextMapper(promptMapper: (ctx: T) => object): void;
15
+ getPromptContextMapper(): (ctx: T) => object;
16
+ }
17
+ export declare function createContext<T extends Ctx>(context: T): Context<T>;
18
+ type Public<T> = {
19
+ [P in keyof T]: T[P];
20
+ };
21
+ type PublicContext<T extends Ctx> = Public<Context<T>>;
22
+ export type { PublicContext as Context };
23
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;AAC9B,KAAK,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,GAC1B;KACK,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC5C,CAAC,MAAM,CAAC,CAAC,GACV,KAAK,CAAA;AAEX,KAAK,SAAS,CAAC,CAAC,EAAE,CAAC,SAAS,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,GACrE,KAAK,SAAS,MAAM,CAAC,GACjB,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,GACpB,CAAC,CAAC,KAAK,CAAC,GACR,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,GAC7B,KAAK,GACT,KAAK,CAAA;AAEX,cAAM,OAAO,CAAC,CAAC,SAAS,GAAG;;gBAIX,OAAO,EAAE,CAAC;IAItB,GAAG,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,SAAS,GAAG,EAAE,GAAG,CAAC,GAAG,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI;IACxF,GAAG,CAAC,UAAU,EAAE,CAAC,GAAG,IAAI;IAgBxB,GAAG;IAKH,IAAI,CAAC,UAAU,EAAE,CAAC;IAIlB,SAAS,GAAI,UAAU,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,mBAG1C;IAED,sBAAsB,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM;IAIvD,sBAAsB,UAxCD,CAAC,KAAK,MAAM;CA2CpC;AAED,wBAAgB,aAAa,CAAC,CAAC,SAAS,GAAG,EAAE,OAAO,EAAE,CAAC,cAEtD;AAED,KAAK,MAAM,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,CAAA;AAEzC,KAAK,aAAa,CAAC,CAAC,SAAS,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;AAEtD,YAAY,EAAE,aAAa,IAAI,OAAO,EAAE,CAAA"}
@@ -0,0 +1,41 @@
1
+ class Context {
2
+ #listeners = new Set();
3
+ #context;
4
+ #promptMapper = (c) => c;
5
+ constructor(context) {
6
+ this.#context = context || {};
7
+ }
8
+ set(pathOrContext, value) {
9
+ if (!Array.isArray(pathOrContext)) {
10
+ this.#context = pathOrContext;
11
+ }
12
+ else {
13
+ const path = pathOrContext;
14
+ let current = this.#context;
15
+ for (let i = 0; i < path.length - 1; i++) {
16
+ current = current[path[i]];
17
+ }
18
+ current[path[path.length - 1]] = value;
19
+ }
20
+ this.#listeners.forEach((listener) => listener(this.#context));
21
+ }
22
+ get() {
23
+ return this.#context;
24
+ }
25
+ swap(newContext) {
26
+ this.#context = newContext;
27
+ }
28
+ subscribe = (listener) => {
29
+ this.#listeners.add(listener);
30
+ return () => this.#listeners.delete(listener);
31
+ };
32
+ setPromptContextMapper(promptMapper) {
33
+ this.#promptMapper = promptMapper;
34
+ }
35
+ getPromptContextMapper() {
36
+ return this.#promptMapper;
37
+ }
38
+ }
39
+ export function createContext(context) {
40
+ return new Context(context);
41
+ }
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=context.spec.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.spec.d.ts","sourceRoot":"","sources":["../src/context.spec.ts"],"names":[],"mappings":""}
@@ -0,0 +1,21 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { createContext } from './context';
3
+ describe('ws-server/context', () => {
4
+ it('sets a value at a path', () => {
5
+ const ctx = createContext({ a: { b: 1 } });
6
+ ctx.set(['a', 'b'], 2);
7
+ expect(ctx.get()).toEqual({ a: { b: 2 } });
8
+ });
9
+ it('sets a new context', () => {
10
+ const ctx = createContext({ a: { b: 1 } });
11
+ ctx.set({ a: { b: 2 } });
12
+ expect(ctx.get()).toEqual({ a: { b: 2 } });
13
+ });
14
+ it('subscribes to context changes', () => {
15
+ const ctx = createContext({ a: { b: 1 } });
16
+ const listener = vi.fn();
17
+ ctx.subscribe(listener);
18
+ ctx.set(['a', 'b'], 2);
19
+ expect(listener).toHaveBeenCalledWith({ a: { b: 2 } });
20
+ });
21
+ });
@@ -0,0 +1,7 @@
1
+ export * from './interfaces/agent';
2
+ export * from './context';
3
+ export * from './mock';
4
+ export * from './test-agent';
5
+ export * from './std-mocks/platform';
6
+ export * from './std-mocks/rc-voice';
7
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,cAAc,oBAAoB,CAAA;AAClC,cAAc,WAAW,CAAA;AACzB,cAAc,QAAQ,CAAA;AACtB,cAAc,cAAc,CAAA;AAC5B,cAAc,sBAAsB,CAAA;AACpC,cAAc,sBAAsB,CAAA"}
package/build/index.js ADDED
@@ -0,0 +1,6 @@
1
+ export * from './interfaces/agent';
2
+ export * from './context';
3
+ export * from './mock';
4
+ export * from './test-agent';
5
+ export * from './std-mocks/platform';
6
+ export * from './std-mocks/rc-voice';
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=index.test.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.test.d.ts","sourceRoot":"","sources":["../src/index.test.ts"],"names":[],"mappings":""}
@@ -0,0 +1,39 @@
1
+ import { Message, Scheduler, StepRegistry } from '@recombine-ai/engine';
2
+ import type { ApiCallTracer, ConversationalTracer, StepTracer } from '@recombine-ai/telescope';
3
+ import { Context } from '../context';
4
+ import { Logger } from './dockyard';
5
+ type DefaultContext = Record<string, any>;
6
+ export interface TestAgentFactoryProps<CTX extends DefaultContext = DefaultContext> {
7
+ stepRegistry: StepRegistry;
8
+ apiCallTracer?: ApiCallTracer;
9
+ conversationalTracer?: ConversationalTracer;
10
+ stepTracer: StepTracer;
11
+ logger: Logger;
12
+ scheduler: Scheduler;
13
+ getMessages: () => Message[];
14
+ sendMessage: (message: string | Message) => Promise<void>;
15
+ ctx: Context<CTX>;
16
+ config: {
17
+ isTest: boolean;
18
+ enableTimers: boolean;
19
+ };
20
+ }
21
+ export interface TestTextAgent {
22
+ start: () => Promise<unknown>;
23
+ reactOnMessage: () => Promise<unknown>;
24
+ respondToMessage: () => Promise<unknown>;
25
+ isAssigned: () => Promise<boolean>;
26
+ onFatalError: (error: Error) => Promise<unknown>;
27
+ }
28
+ export interface TestVoiceAgent {
29
+ streamResponse: () => Promise<unknown>;
30
+ onCallEnd: () => Promise<unknown>;
31
+ onCallStart: () => Promise<unknown>;
32
+ onFatalError: (error: Error) => Promise<unknown>;
33
+ waitForIdle: () => Promise<void>;
34
+ }
35
+ export type TestAgent = TestTextAgent | TestVoiceAgent;
36
+ export type TestAgentFactory<T extends DefaultContext = DefaultContext> = (props: TestAgentFactoryProps<T>) => Promise<TestAgent>;
37
+ export declare function createTestAgentFactory<T extends DefaultContext>(creator: TestAgentFactory<T>): TestAgentFactory<T>;
38
+ export {};
39
+ //# sourceMappingURL=agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"agent.d.ts","sourceRoot":"","sources":["../../src/interfaces/agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,YAAY,EAAE,MAAM,sBAAsB,CAAA;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,yBAAyB,CAAA;AAE9F,OAAO,EAAE,OAAO,EAAE,MAAM,YAAY,CAAA;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAuBnC,KAAK,cAAc,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;AACzC,MAAM,WAAW,qBAAqB,CAAC,GAAG,SAAS,cAAc,GAAG,cAAc;IAC9E,YAAY,EAAE,YAAY,CAAA;IAM1B,aAAa,CAAC,EAAE,aAAa,CAAA;IAM7B,oBAAoB,CAAC,EAAE,oBAAoB,CAAA;IAC3C,UAAU,EAAE,UAAU,CAAA;IACtB,MAAM,EAAE,MAAM,CAAA;IACd,SAAS,EAAE,SAAS,CAAA;IACpB,WAAW,EAAE,MAAM,OAAO,EAAE,CAAA;IAC5B,WAAW,EAAE,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACzD,GAAG,EAAE,OAAO,CAAC,GAAG,CAAC,CAAA;IACjB,MAAM,EAAE;QACJ,MAAM,EAAE,OAAO,CAAA;QACf,YAAY,EAAE,OAAO,CAAA;KACxB,CAAA;CACJ;AAED,MAAM,WAAW,aAAa;IAC1B,KAAK,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IAC7B,cAAc,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IACtC,gBAAgB,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IACxC,UAAU,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IAClC,YAAY,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CACnD;AAED,MAAM,WAAW,cAAc;IAC3B,cAAc,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IACtC,SAAS,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IACjC,WAAW,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,CAAA;IACnC,YAAY,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IAChD,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;CACnC;AAED,MAAM,MAAM,SAAS,GAAG,aAAa,GAAG,cAAc,CAAA;AAEtD,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,cAAc,GAAG,cAAc,IAAI,CACtE,KAAK,EAAE,qBAAqB,CAAC,CAAC,CAAC,KAC9B,OAAO,CAAC,SAAS,CAAC,CAAA;AAEvB,wBAAgB,sBAAsB,CAAC,CAAC,SAAS,cAAc,EAAE,OAAO,EAAE,gBAAgB,CAAC,CAAC,CAAC,uBAE5F"}
@@ -0,0 +1,3 @@
1
+ export function createTestAgentFactory(creator) {
2
+ return creator;
3
+ }
@@ -0,0 +1,23 @@
1
+ type Ctx = Record<string, any>;
2
+ type Paths<T> = T extends object ? {
3
+ [K in keyof T]: [K] | [K, ...Paths<T[K]>];
4
+ }[keyof T] : never;
5
+ type PathValue<T, P extends any[]> = P extends [infer First, ...infer Rest] ? First extends keyof T ? Rest['length'] extends 0 ? T[First] : PathValue<T[First], Rest> : never : never;
6
+ declare class Context<T extends Ctx> {
7
+ #private;
8
+ constructor(context: T);
9
+ set<P extends Paths<T>>(path: P extends any[] ? P : never, value: PathValue<T, P>): void;
10
+ set(newContext: T): void;
11
+ get(): T;
12
+ swap(newContext: T): void;
13
+ subscribe: (listener: (context: T) => void) => () => boolean;
14
+ setPromptContextMapper(promptMapper: (ctx: T) => object): void;
15
+ getPromptContextMapper(): (ctx: T) => object;
16
+ }
17
+ export declare function createContext<T extends Ctx>(context: T): Context<T>;
18
+ type Public<T> = {
19
+ [P in keyof T]: T[P];
20
+ };
21
+ type PublicContext<T extends Ctx> = Public<Context<T>>;
22
+ export type { PublicContext as Context };
23
+ //# sourceMappingURL=context.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../../src/interfaces/context.ts"],"names":[],"mappings":"AAAA,KAAK,GAAG,GAAG,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;AAC9B,KAAK,KAAK,CAAC,CAAC,IAAI,CAAC,SAAS,MAAM,GAC1B;KACK,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,GAAG,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;CAC5C,CAAC,MAAM,CAAC,CAAC,GACV,KAAK,CAAA;AAEX,KAAK,SAAS,CAAC,CAAC,EAAE,CAAC,SAAS,GAAG,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,KAAK,EAAE,GAAG,MAAM,IAAI,CAAC,GACrE,KAAK,SAAS,MAAM,CAAC,GACjB,IAAI,CAAC,QAAQ,CAAC,SAAS,CAAC,GACpB,CAAC,CAAC,KAAK,CAAC,GACR,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,EAAE,IAAI,CAAC,GAC7B,KAAK,GACT,KAAK,CAAA;AAEX,cAAM,OAAO,CAAC,CAAC,SAAS,GAAG;;gBAIX,OAAO,EAAE,CAAC;IAItB,GAAG,CAAC,CAAC,SAAS,KAAK,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,SAAS,GAAG,EAAE,GAAG,CAAC,GAAG,KAAK,EAAE,KAAK,EAAE,SAAS,CAAC,CAAC,EAAE,CAAC,CAAC,GAAG,IAAI;IACxF,GAAG,CAAC,UAAU,EAAE,CAAC,GAAG,IAAI;IAgBxB,GAAG;IAKH,IAAI,CAAC,UAAU,EAAE,CAAC;IAIlB,SAAS,GAAI,UAAU,CAAC,OAAO,EAAE,CAAC,KAAK,IAAI,mBAG1C;IAED,sBAAsB,CAAC,YAAY,EAAE,CAAC,GAAG,EAAE,CAAC,KAAK,MAAM;IAIvD,sBAAsB,UAxCD,CAAC,KAAK,MAAM;CA2CpC;AAED,wBAAgB,aAAa,CAAC,CAAC,SAAS,GAAG,EAAE,OAAO,EAAE,CAAC,cAEtD;AAED,KAAK,MAAM,CAAC,CAAC,IAAI;KAAG,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC;CAAE,CAAA;AAEzC,KAAK,aAAa,CAAC,CAAC,SAAS,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,CAAC,CAAC,CAAA;AAEtD,YAAY,EAAE,aAAa,IAAI,OAAO,EAAE,CAAA"}
@@ -0,0 +1,6 @@
1
+ export interface Logger {
2
+ log: (...args: any[]) => void;
3
+ debug: (...args: any[]) => void;
4
+ error: (...args: any[]) => void;
5
+ }
6
+ //# sourceMappingURL=dockyard.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dockyard.d.ts","sourceRoot":"","sources":["../../src/interfaces/dockyard.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,MAAM;IACnB,GAAG,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IAC7B,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;IAC/B,KAAK,EAAE,CAAC,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,IAAI,CAAA;CAClC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,6 @@
1
+ import { Logger } from './dockyard';
2
+ type ConstructorType<T> = new (...args: any[]) => T;
3
+ type InstanceType<T extends ConstructorType<any>> = T extends new (...args: any[]) => infer R ? R : never;
4
+ export declare function createMock<T extends ConstructorType<any>>(logger: Logger, constructor: T, overrides?: Partial<InstanceType<T>>): InstanceType<T>;
5
+ export {};
6
+ //# sourceMappingURL=mock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../../src/interfaces/mock.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,YAAY,CAAA;AAEnC,KAAK,eAAe,CAAC,CAAC,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAA;AACnD,KAAK,YAAY,CAAC,CAAC,SAAS,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,MAAM,CAAC,GACvF,CAAC,GACD,KAAK,CAAA;AAEX,wBAAgB,UAAU,CAAC,CAAC,SAAS,eAAe,CAAC,GAAG,CAAC,EACrD,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,CAAC,EACd,SAAS,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GACrC,YAAY,CAAC,CAAC,CAAC,CAuBjB"}
@@ -0,0 +1,19 @@
1
+ export type ScheduleAction = (delay: Date, phone: string) => Promise<void>;
2
+ export interface Scheduler {
3
+ registerAction: (actionName: string, action: (phone: string) => Promise<unknown>) => ScheduleAction;
4
+ clearAllPendingActions: (phone: string) => Promise<unknown>;
5
+ }
6
+ export interface PromptFile {
7
+ type: 'file';
8
+ content: () => Promise<string>;
9
+ path: string;
10
+ }
11
+ export interface PromptFS {
12
+ loadFile(path: string): PromptFile;
13
+ }
14
+ export interface Message {
15
+ sender: 'user' | 'agent' | 'system';
16
+ text: string;
17
+ imageUrl?: string;
18
+ }
19
+ //# sourceMappingURL=other.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"other.d.ts","sourceRoot":"","sources":["../../src/interfaces/other.ts"],"names":[],"mappings":"AAQA,MAAM,MAAM,cAAc,GAAG,CAAC,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;AAE1E,MAAM,WAAW,SAAS;IAOtB,cAAc,EAAE,CACZ,UAAU,EAAE,MAAM,EAClB,MAAM,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,KAC1C,cAAc,CAAA;IAKnB,sBAAsB,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;CAC9D;AAED,MAAM,WAAW,UAAU;IACvB,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;IAC9B,IAAI,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,QAAQ;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,UAAU,CAAA;CACrC;AASD,MAAM,WAAW,OAAO;IAEpB,MAAM,EAAE,MAAM,GAAG,OAAO,GAAG,QAAQ,CAAA;IAEnC,IAAI,EAAE,MAAM,CAAA;IAEZ,QAAQ,CAAC,EAAE,MAAM,CAAA;CACpB"}
@@ -0,0 +1,16 @@
1
+ import { type ZodType } from 'zod';
2
+ import { PromptFile } from './other';
3
+ export interface PromptString {
4
+ type: 'string';
5
+ content: () => Promise<string>;
6
+ }
7
+ export interface StepDef {
8
+ name: string;
9
+ type: 'streaming-response' | 'streaming-detect' | 'text';
10
+ prompt: PromptFile | PromptString;
11
+ schema?: ZodType;
12
+ }
13
+ export interface StepRegistry {
14
+ addStep(def: StepDef): void;
15
+ }
16
+ //# sourceMappingURL=step-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"step-registry.d.ts","sourceRoot":"","sources":["../../src/interfaces/step-registry.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,OAAO,EAAE,MAAM,KAAK,CAAA;AAGlC,OAAO,EAAE,UAAU,EAAE,MAAM,SAAS,CAAA;AAEpC,MAAM,WAAW,YAAY;IACzB,IAAI,EAAE,QAAQ,CAAA;IACd,OAAO,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAA;CACjC;AAED,MAAM,WAAW,OAAO;IACpB,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,oBAAoB,GAAG,kBAAkB,GAAG,MAAM,CAAA;IACxD,MAAM,EAAE,UAAU,GAAG,YAAY,CAAA;IACjC,MAAM,CAAC,EAAE,OAAO,CAAA;CACnB;AAED,MAAM,WAAW,YAAY;IACzB,OAAO,CAAC,GAAG,EAAE,OAAO,GAAG,IAAI,CAAA;CAC9B"}
@@ -0,0 +1,6 @@
1
+ import { Logger } from './interfaces/dockyard';
2
+ type ConstructorType<T> = new (...args: any[]) => T;
3
+ type InstanceType<T extends ConstructorType<any>> = T extends new (...args: any[]) => infer R ? R : never;
4
+ export declare function createMock<T extends ConstructorType<any>>(logger: Logger, constructor: T, overrides?: Partial<InstanceType<T>>): InstanceType<T>;
5
+ export {};
6
+ //# sourceMappingURL=mock.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mock.d.ts","sourceRoot":"","sources":["../src/mock.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAA;AAE9C,KAAK,eAAe,CAAC,CAAC,IAAI,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,CAAC,CAAA;AACnD,KAAK,YAAY,CAAC,CAAC,SAAS,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,SAAS,KAAK,GAAG,IAAI,EAAE,GAAG,EAAE,KAAK,MAAM,CAAC,GACvF,CAAC,GACD,KAAK,CAAA;AAEX,wBAAgB,UAAU,CAAC,CAAC,SAAS,eAAe,CAAC,GAAG,CAAC,EACrD,MAAM,EAAE,MAAM,EACd,WAAW,EAAE,CAAC,EACd,SAAS,CAAC,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC,GACrC,YAAY,CAAC,CAAC,CAAC,CAuBjB"}
package/build/mock.js ADDED
@@ -0,0 +1,28 @@
1
+ import { inspect } from 'node:util';
2
+ export function createMock(logger, constructor, overrides) {
3
+ const mock = Object.create(constructor.prototype);
4
+ const properties = Object.getOwnPropertyDescriptors(constructor.prototype);
5
+ for (const [key, descriptor] of Object.entries(properties)) {
6
+ if (typeof descriptor.value === 'function' && key !== 'constructor') {
7
+ mock[key] = function (...args) {
8
+ let returnValue = {};
9
+ if (overrides && key in overrides && typeof overrides[key] === 'function') {
10
+ returnValue = overrides[key](...args);
11
+ }
12
+ const logs = [`${constructor.name}.${key}\n\tCalled with:`, prettyArgs(args)];
13
+ if (returnValue) {
14
+ logs.push(`\n\tReturning: ${prettyInspect(returnValue)}`);
15
+ }
16
+ logger.log(...logs);
17
+ return returnValue;
18
+ };
19
+ }
20
+ }
21
+ return mock;
22
+ }
23
+ function prettyArgs(args) {
24
+ return args.map((arg) => (typeof arg === 'object' ? prettyInspect(arg) : arg)).join(' ');
25
+ }
26
+ function prettyInspect(obj) {
27
+ return inspect(obj, { depth: null }).split('\n').join('\n\t');
28
+ }
@@ -0,0 +1,8 @@
1
+ import { IModels, Platform } from '@recombine-ai/platform';
2
+ import { TestAgentFactoryProps, TestVoiceAgent } from '../interfaces/agent';
3
+ export declare function getPlatformMocks<TContext extends {}, TModels extends IModels>(props: TestAgentFactoryProps<any>, models: TModels, basePath: string): Promise<{
4
+ platform: Platform<TContext, TModels>;
5
+ setLoopBack(this: void, bosunAgent: TestVoiceAgent): void;
6
+ waitForIdle: () => Promise<void>;
7
+ }>;
8
+ //# sourceMappingURL=platform.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"platform.d.ts","sourceRoot":"","sources":["../../src/std-mocks/platform.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAuC,MAAM,wBAAwB,CAAA;AAE/F,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,qBAAqB,CAAA;AAG3E,wBAAsB,gBAAgB,CAAC,QAAQ,SAAS,EAAE,EAAE,OAAO,SAAS,OAAO,EAC/E,KAAK,EAAE,qBAAqB,CAAC,GAAG,CAAC,EACjC,MAAM,EAAE,OAAO,EACf,QAAQ,EAAE,MAAM;;sBAoCM,IAAI,cAAc,cAAc;;GAMzD"}
@@ -0,0 +1,37 @@
1
+ import { createAIEngine, createAIStreamEngine, createLocalFS } from '@recombine-ai/engine';
2
+ import { TimeoutManager, createInMemoryCache } from '@recombine-ai/platform';
3
+ import { createRcVoiceMock } from './rc-voice';
4
+ export async function getPlatformMocks(props, models, basePath) {
5
+ const streamAi = createAIStreamEngine({
6
+ logger: props.logger,
7
+ stepRegistry: props.stepRegistry,
8
+ stepTracer: props.stepTracer,
9
+ });
10
+ const ai = createAIEngine({
11
+ logger: props.logger,
12
+ stepRegistry: props.stepRegistry,
13
+ stepTracer: props.stepTracer,
14
+ });
15
+ const rcVoiceMock = createRcVoiceMock(props);
16
+ const platform = {
17
+ streamAi,
18
+ ai,
19
+ fs: createLocalFS({
20
+ logger: props.logger,
21
+ basePath,
22
+ }),
23
+ logger: props.logger,
24
+ rcVoice: rcVoiceMock.rcVoice,
25
+ timeoutManager: new TimeoutManager(createInMemoryCache(), props.logger, !props.config.enableTimers),
26
+ contextCache: createInMemoryCache(),
27
+ ...models,
28
+ };
29
+ return {
30
+ platform,
31
+ setLoopBack(bosunAgent) {
32
+ rcVoiceMock.setCallEnd(bosunAgent.onCallEnd);
33
+ rcVoiceMock.setReload(bosunAgent.streamResponse);
34
+ },
35
+ waitForIdle: rcVoiceMock.waitForIdle,
36
+ };
37
+ }
@@ -0,0 +1,11 @@
1
+ import { IRcVoice, VoiceAgentConnector } from '@recombine-ai/platform';
2
+ import { TestAgentFactoryProps } from '../interfaces/agent';
3
+ interface RcVoiceCompatibleMock {
4
+ rcVoice: IRcVoice & VoiceAgentConnector;
5
+ waitForIdle: () => Promise<void>;
6
+ setReload: (_onReload: () => Promise<unknown>) => void;
7
+ setCallEnd: (_onReload: () => Promise<unknown>) => void;
8
+ }
9
+ export declare function createRcVoiceMock(props: TestAgentFactoryProps<object>): RcVoiceCompatibleMock;
10
+ export {};
11
+ //# sourceMappingURL=rc-voice.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rc-voice.d.ts","sourceRoot":"","sources":["../../src/std-mocks/rc-voice.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,QAAQ,EAAkB,mBAAmB,EAAE,MAAM,wBAAwB,CAAA;AAEtF,OAAO,EAAE,qBAAqB,EAAE,MAAM,qBAAqB,CAAA;AAE3D,UAAU,qBAAqB;IAC3B,OAAO,EAAE,QAAQ,GAAG,mBAAmB,CAAA;IACvC,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAA;IAChC,SAAS,EAAE,CAAC,SAAS,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAA;IACtD,UAAU,EAAE,CAAC,SAAS,EAAE,MAAM,OAAO,CAAC,OAAO,CAAC,KAAK,IAAI,CAAA;CAC1D;AAED,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,qBAAqB,CAAC,MAAM,CAAC,GAAG,qBAAqB,CAiI7F"}
@@ -0,0 +1,137 @@
1
+ export function createRcVoiceMock(props) {
2
+ let onReload;
3
+ let onCallEnd;
4
+ let inFlight = 0;
5
+ let idleResolvers = [];
6
+ function trackReload() {
7
+ inFlight++;
8
+ setTimeout(() => {
9
+ onReload?.()
10
+ .catch((err) => {
11
+ props.logger.error('RcVoice: reload failed', { err });
12
+ })
13
+ .finally(() => {
14
+ inFlight--;
15
+ if (inFlight === 0) {
16
+ const resolvers = idleResolvers;
17
+ idleResolvers = [];
18
+ resolvers.forEach((r) => r());
19
+ }
20
+ });
21
+ });
22
+ }
23
+ function waitForIdle() {
24
+ if (inFlight === 0)
25
+ return Promise.resolve();
26
+ return new Promise((resolve) => idleResolvers.push(resolve));
27
+ }
28
+ return {
29
+ rcVoice: {
30
+ async hangup(callId) {
31
+ await onCallEnd?.();
32
+ props.conversationalTracer?.addConversationalTrace({
33
+ conversationId: callId,
34
+ eventName: 'hangup-requested',
35
+ role: 'agent',
36
+ medium: 'phone',
37
+ content: 'hangup',
38
+ createdAt: Date.now(),
39
+ });
40
+ await props.conversationalTracer?.flush();
41
+ },
42
+ async transfer(destOrName, callIdOdDest, headersOrCallId) {
43
+ let callId = callIdOdDest;
44
+ let destination = destOrName;
45
+ if (typeof headersOrCallId === 'string') {
46
+ callId = headersOrCallId;
47
+ destination = callIdOdDest;
48
+ }
49
+ props.conversationalTracer?.addConversationalTrace({
50
+ conversationId: callId,
51
+ eventName: 'transfer-requested',
52
+ role: 'agent',
53
+ medium: 'phone',
54
+ content: destination,
55
+ createdAt: Date.now(),
56
+ });
57
+ await props.conversationalTracer?.flush();
58
+ },
59
+ async reload(_) {
60
+ props.logger.log('RcVoice: reload');
61
+ await sleep(100);
62
+ trackReload();
63
+ },
64
+ async addMessage(_, message) {
65
+ await sleep(500);
66
+ await props.sendMessage(message);
67
+ },
68
+ async steer(_, payload) {
69
+ props.logger.log('RcVoice: steer');
70
+ await sleep(500);
71
+ for (const message of payload.addMessages ?? []) {
72
+ await props.sendMessage(message);
73
+ }
74
+ if (payload.respond) {
75
+ trackReload();
76
+ }
77
+ },
78
+ async getCallDetails() {
79
+ props.logger.log('RcVoice: getCallDetails');
80
+ return {
81
+ callId: '',
82
+ callDuration: 102,
83
+ callEnd: '',
84
+ callStart: '',
85
+ endedReason: '',
86
+ messages: props.getMessages(),
87
+ error: null,
88
+ recording: null,
89
+ transcript: props
90
+ .getMessages()
91
+ .filter((m) => m.sender !== 'system')
92
+ .map(mapToTranscript),
93
+ };
94
+ },
95
+ async setVoiceSetting(settings) {
96
+ props.logger.log('RcVoice: setVoiceSetting', { settings });
97
+ },
98
+ async setUpSip(...args) {
99
+ if (args.length) {
100
+ props.logger.log('RcVoice: setUpSip', { name: args[0], trunks: args[1] });
101
+ }
102
+ else {
103
+ props.logger.log('RcVoice: setUpSip');
104
+ }
105
+ },
106
+ async freeze() {
107
+ props.logger.log('RcVoice: freeze');
108
+ },
109
+ async unfreeze() {
110
+ props.logger.log('RcVoice: unfreeze');
111
+ },
112
+ async setVoiceSettings(settings) {
113
+ props.logger.log('RcVoice: setVoiceSettings', { settings });
114
+ },
115
+ },
116
+ setReload(_onReload) {
117
+ onReload = _onReload;
118
+ },
119
+ setCallEnd(_onCallEnd) {
120
+ onCallEnd = _onCallEnd;
121
+ },
122
+ waitForIdle,
123
+ };
124
+ }
125
+ function sleep(t) {
126
+ if (process.env.IS_TEST === 'true')
127
+ return Promise.resolve();
128
+ return new Promise((r) => setTimeout(r, t));
129
+ }
130
+ function mapToTranscript(m) {
131
+ return {
132
+ text: m.text,
133
+ role: m.sender === 'agent' ? 'Agent' : 'User',
134
+ time: 'unknown',
135
+ duration: 0,
136
+ };
137
+ }
@@ -0,0 +1,4 @@
1
+ import { Logger } from './interfaces/dockyard';
2
+ import { StepRegistry } from './interfaces/step-registry';
3
+ export declare function createStubRegistry(logger: Logger): StepRegistry;
4
+ //# sourceMappingURL=stubs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"stubs.d.ts","sourceRoot":"","sources":["../src/stubs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,EAAE,MAAM,uBAAuB,CAAA;AAC9C,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAA;AAKzD,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,MAAM,GAAG,YAAY,CAM/D"}
@@ -0,0 +1,4 @@
1
+ import { CallInfo, VoiceAgent } from '@recombine-ai/platform';
2
+ import { TestAgentFactoryProps, TestVoiceAgent } from './interfaces/agent';
3
+ export declare function makeTestVoiceAgent(props: TestAgentFactoryProps<any>, agent: VoiceAgent, waitForIdle: () => Promise<void>, testCall: CallInfo): TestVoiceAgent;
4
+ //# sourceMappingURL=test-agent.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-agent.d.ts","sourceRoot":"","sources":["../src/test-agent.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,UAAU,EAAE,MAAM,wBAAwB,CAAA;AAE7D,OAAO,EAAE,qBAAqB,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAA;AAG1E,wBAAgB,kBAAkB,CAC9B,KAAK,EAAE,qBAAqB,CAAC,GAAG,CAAC,EACjC,KAAK,EAAE,UAAU,EACjB,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,EAChC,QAAQ,EAAE,QAAQ,GACnB,cAAc,CAmEhB"}
@@ -0,0 +1,70 @@
1
+ import { collectStream } from './utils';
2
+ export function makeTestVoiceAgent(props, agent, waitForIdle, testCall) {
3
+ async function streamResponse() {
4
+ const messages = props.getMessages();
5
+ if (props.conversationalTracer) {
6
+ const lastMessage = messages.at(-1);
7
+ const lastText = lastMessage?.text ?? '';
8
+ const lastRole = lastMessage?.sender ?? 'user';
9
+ try {
10
+ props.conversationalTracer.addConversationalTrace({
11
+ conversationId: testCall.callId,
12
+ eventName: 'llm-handler-stream-requested',
13
+ role: lastRole,
14
+ medium: 'phone',
15
+ content: lastText,
16
+ createdAt: Date.now(),
17
+ });
18
+ await props.conversationalTracer.flush();
19
+ }
20
+ catch (err) {
21
+ props.logger.error('Failed to write conversational trace', { err });
22
+ }
23
+ }
24
+ const reply = await collectStream(await agent.streamResponse(messages, testCall));
25
+ await props.sendMessage(reply);
26
+ try {
27
+ props.conversationalTracer?.addConversationalTrace({
28
+ conversationId: testCall.callId,
29
+ eventName: 'finished-main-streaming-step',
30
+ role: 'agent',
31
+ medium: 'phone',
32
+ content: reply,
33
+ createdAt: Date.now(),
34
+ });
35
+ await props.conversationalTracer?.flush();
36
+ }
37
+ catch (err) {
38
+ props.logger.error('Failed to write conversational trace', { err });
39
+ }
40
+ await agent.onAgentSpeechDone(props.getMessages(), testCall);
41
+ }
42
+ return {
43
+ streamResponse: streamResponse,
44
+ onCallStart: async () => {
45
+ await agent.onCallStart(testCall);
46
+ await agent.onCallReady(testCall);
47
+ },
48
+ onCallEnd: async () => {
49
+ try {
50
+ props.conversationalTracer?.addConversationalTrace({
51
+ conversationId: testCall.callId,
52
+ eventName: 'hangup-requested',
53
+ role: 'agent',
54
+ medium: 'phone',
55
+ content: 'hangup',
56
+ createdAt: Date.now(),
57
+ });
58
+ await props.conversationalTracer?.flush();
59
+ }
60
+ catch (err) {
61
+ props.logger.error('Failed to write conversational trace', { err });
62
+ }
63
+ await agent.onCallEnd(testCall);
64
+ },
65
+ waitForIdle,
66
+ async onFatalError(error) {
67
+ props.logger.error(error);
68
+ },
69
+ };
70
+ }
@@ -0,0 +1,4 @@
1
+ export declare function collectStream(stream: ReadableStream<{
2
+ delta: string;
3
+ }>): Promise<string>;
4
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,wBAAsB,aAAa,CAAC,MAAM,EAAE,cAAc,CAAC;IAAE,KAAK,EAAE,MAAM,CAAA;CAAE,CAAC,mBAM5E"}
package/build/utils.js ADDED
@@ -0,0 +1,7 @@
1
+ export async function collectStream(stream) {
2
+ const result = [];
3
+ for await (const chunk of stream) {
4
+ result.push(chunk.delta);
5
+ }
6
+ return result.join('');
7
+ }
package/package.json ADDED
@@ -0,0 +1,30 @@
1
+ {
2
+ "name": "@recombine-ai/bosun-lib",
3
+ "version": "0.1.0",
4
+ "description": "Bosun conversational agents IDE bindings to agents build on Recombine platform",
5
+ "license": "EULA",
6
+ "author": "recombine.ai",
7
+ "repository": {
8
+ "type": "git",
9
+ "url": "https://github.com/recombine-ai/platform.git",
10
+ "directory": "packages/bosun-lib"
11
+ },
12
+ "files": [
13
+ "build"
14
+ ],
15
+ "type": "module",
16
+ "dependencies": {
17
+ "@recombine-ai/engine": "1.0.0",
18
+ "@recombine-ai/telescope": "0.1.0",
19
+ "zod": "^4.4.3"
20
+ },
21
+ "exports": {
22
+ ".": "./src/index.ts"
23
+ },
24
+ "publishConfig": {
25
+ "registry": "https://registry.npmjs.org"
26
+ },
27
+ "devDependencies": {
28
+ "@types/node": "^25.2.3"
29
+ }
30
+ }