libmodulor 0.21.0 → 0.22.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 (69) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +1 -1
  3. package/dist/esm/apps/Helper/src/lib/project.js +7 -7
  4. package/dist/esm/apps/Helper/src/ucds/CreateProjectUCD.d.ts +1 -0
  5. package/dist/esm/apps/Helper/src/ucds/CreateProjectUCD.js +20 -13
  6. package/dist/esm/dt/DataType.d.ts +2 -1
  7. package/dist/esm/dt/DataTypes.js +1 -0
  8. package/dist/esm/dt/final/TTransportType.d.ts +8 -0
  9. package/dist/esm/dt/final/TTransportType.js +16 -0
  10. package/dist/esm/dt/index.d.ts +1 -0
  11. package/dist/esm/dt/index.js +1 -0
  12. package/dist/esm/error/funcs.d.ts +2 -0
  13. package/dist/esm/error/funcs.js +19 -0
  14. package/dist/esm/error/index.d.ts +1 -0
  15. package/dist/esm/error/index.js +1 -0
  16. package/dist/esm/index.d.ts +2 -0
  17. package/dist/esm/index.js +2 -0
  18. package/dist/esm/std/HTTPAPICallExecutor.d.ts +16 -7
  19. package/dist/esm/std/HTTPAPICaller.d.ts +8 -1
  20. package/dist/esm/std/LLMManager.d.ts +20 -3
  21. package/dist/esm/std/impl/FakeClockManager.d.ts +6 -0
  22. package/dist/esm/std/impl/FakeClockManager.js +19 -0
  23. package/dist/esm/std/impl/FakeHTTPAPICallExecutor.js +19 -18
  24. package/dist/esm/std/impl/FakeLLMManager.d.ts +4 -0
  25. package/dist/esm/std/impl/FakeLLMManager.js +40 -0
  26. package/dist/esm/std/impl/MistralAILLMManager.js +12 -0
  27. package/dist/esm/std/impl/OllamaLLMManager.d.ts +7 -2
  28. package/dist/esm/std/impl/OllamaLLMManager.js +32 -5
  29. package/dist/esm/std/impl/OpenAILLMManager.js +9 -0
  30. package/dist/esm/std/impl/SimpleHTTPAPICaller.d.ts +7 -3
  31. package/dist/esm/std/impl/SimpleHTTPAPICaller.js +66 -15
  32. package/dist/esm/target/lib/cli/CommandExecutor.js +9 -1
  33. package/dist/esm/target/lib/react/UCPanel.d.ts +4 -2
  34. package/dist/esm/target/lib/react/UCPanel.js +2 -2
  35. package/dist/esm/target/lib/server/ServerRequestHandler.d.ts +3 -2
  36. package/dist/esm/target/lib/server/ServerRequestHandler.js +2 -2
  37. package/dist/esm/target/lib/server-express/funcs.js +52 -1
  38. package/dist/esm/target/lib/server-hono/funcs.js +65 -2
  39. package/dist/esm/testing/workers/UCExecutor.js +39 -1
  40. package/dist/esm/uc/ext.d.ts +7 -1
  41. package/dist/esm/uc/impl/HTTPUCTransporter.d.ts +2 -2
  42. package/dist/esm/uc/impl/HTTPUCTransporter.js +3 -1
  43. package/dist/esm/uc/impl/SimpleUCManager.d.ts +3 -3
  44. package/dist/esm/uc/impl/SimpleUCManager.js +23 -4
  45. package/dist/esm/uc/lifecycle/client/SendClientMain.d.ts +1 -1
  46. package/dist/esm/uc/lifecycle/client/SendClientMain.js +5 -2
  47. package/dist/esm/uc/main.d.ts +8 -1
  48. package/dist/esm/uc/manager.d.ts +11 -2
  49. package/dist/esm/uc/output.d.ts +1 -0
  50. package/dist/esm/uc/output.js +10 -1
  51. package/dist/esm/uc/transporter.d.ts +7 -1
  52. package/dist/esm/utils/async/types.d.ts +2 -0
  53. package/dist/esm/utils/async/types.js +1 -0
  54. package/dist/esm/utils/http/NDJSONStreamManager.d.ts +12 -0
  55. package/dist/esm/utils/http/NDJSONStreamManager.js +42 -0
  56. package/dist/esm/utils/http/SSEStreamManager.d.ts +12 -0
  57. package/dist/esm/utils/http/SSEStreamManager.js +57 -0
  58. package/dist/esm/utils/http/nd-json.d.ts +1 -0
  59. package/dist/esm/utils/http/nd-json.js +2 -0
  60. package/dist/esm/utils/http/sse.d.ts +14 -0
  61. package/dist/esm/utils/http/sse.js +24 -0
  62. package/dist/esm/utils/http/status.d.ts +4 -0
  63. package/dist/esm/utils/http/status.js +9 -0
  64. package/dist/esm/utils/index.d.ts +6 -0
  65. package/dist/esm/utils/index.js +4 -0
  66. package/dist/esm/utils/streams/types.d.ts +17 -0
  67. package/dist/esm/utils/streams/types.js +1 -0
  68. package/package.json +15 -15
  69. package/pnpm-workspace.yaml +1 -0
package/CHANGELOG.md CHANGED
@@ -1,5 +1,18 @@
1
1
  # CHANGELOG
2
2
 
3
+ ## v0.22.0 (2025-10-25)
4
+
5
+ **Added**
6
+
7
+ - Add `verbose` option to `CreateProject` : `pnpm libmodulor CreateProject --outPath ~/Downloads --projectName libmodulor-test --verbose`
8
+ - Add stream ability to `LLMManager`
9
+ - Introduce stream output to use cases : set `transportType: 'stream'` in `ucd.def.http` and send partial output in your `ServerMain` so your clients can start showing data before the processing is done
10
+ - Use stream from client to server
11
+ - Add `FakeClockManager` and `FakeLLMManager` to `std` : they are now centralized so they can be reused by all the apps instead of duplicating them
12
+ - Handle targets without fetch stream capabilities
13
+ - Stream responses in cli targets
14
+ - Add ability to abort UC execution
15
+
3
16
  ## v0.21.0 (2025-08-19)
4
17
 
5
18
  **BREAKING**
package/README.md CHANGED
@@ -17,4 +17,4 @@ If you think you can help in any way, feel free to contact me (cf. `author` in `
17
17
 
18
18
  ## ⚖️ License
19
19
 
20
- [LGPL-3.0](https://github.com/c100k/libmodulor/blob/v0.21.0/LICENSE)
20
+ [LGPL-3.0](https://github.com/c100k/libmodulor/blob/v0.22.0/LICENSE)
@@ -81,23 +81,23 @@ export const PACKAGE_JSON = (name) => `{
81
81
  "test": "tsc && vitest run --passWithNoTests"
82
82
  },
83
83
  "dependencies": {
84
- "inversify": "^7.8.1",
84
+ "inversify": "^7.10.3",
85
85
  "libmodulor": "latest",
86
86
  "reflect-metadata": "^0.2.2"
87
87
  },
88
88
  "devDependencies": {
89
- "@biomejs/biome": "^2.2.0",
90
- "@types/node": "^22.17.2",
89
+ "@biomejs/biome": "^2.2.7",
90
+ "@types/node": "^24.9.1",
91
91
  "@vitest/coverage-v8": "^3.2.4",
92
92
  "buffer": "^6.0.3",
93
93
  "cookie-parser": "^1.4.7",
94
94
  "express": "^5.1.0",
95
95
  "express-fileupload": "^1.5.2",
96
- "fast-check": "^4.2.0",
96
+ "fast-check": "^4.3.0",
97
97
  "helmet": "^8.1.0",
98
- "jose": "^6.0.12",
99
- "typescript": "^5.9.2",
100
- "vite": "^6.3.5",
98
+ "jose": "^6.1.0",
99
+ "typescript": "^5.9.3",
100
+ "vite": "^6.4.1",
101
101
  "vitest": "^3.2.4"
102
102
  }
103
103
  }
@@ -7,6 +7,7 @@ export interface CreateProjectInput extends UCInput {
7
7
  pkgManagerBin: UCInputFieldValue<FileName>;
8
8
  projectName: UCInputFieldValue<Slug>;
9
9
  scmBin: UCInputFieldValue<FileName>;
10
+ verbose: UCInputFieldValue<boolean>;
10
11
  }
11
12
  export declare class CreateProjectClientMain implements UCMain<CreateProjectInput> {
12
13
  private fsManager;
@@ -12,7 +12,7 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
12
12
  };
13
13
  import { inject, injectable } from 'inversify';
14
14
  import { APPS_ROOT_PATH, PRODUCTS_ROOT_PATH } from '../../../../convention.js';
15
- import { TDirPath, TFileName, TFreeTextShort, TSlug, } from '../../../../dt/index.js';
15
+ import { TBoolean, TDirPath, TFileName, TFreeTextShort, TSlug, } from '../../../../dt/index.js';
16
16
  import { IllegalArgumentError } from '../../../../error/index.js';
17
17
  import { EverybodyUCPolicy, } from '../../../../uc/index.js';
18
18
  import { projectFiles } from '../lib/project.js';
@@ -32,17 +32,18 @@ let CreateProjectClientMain = class CreateProjectClientMain {
32
32
  const pkgManagerBin = uc.reqVal0('pkgManagerBin');
33
33
  const projectName = uc.reqVal0('projectName');
34
34
  const scmBin = uc.reqVal0('scmBin');
35
+ const verbose = uc.reqVal0('verbose');
35
36
  await this.assertBinPresence(pkgManagerBin);
36
37
  await this.assertBinPresence(scmBin);
37
38
  const cwd = this.fsManager.path(outPath, projectName);
38
39
  // TODO : Rollback the whole thing in case of failure
39
40
  await this.createRootDir(cwd);
40
- await this.initRepository(scmBin, cwd);
41
+ await this.initRepository(scmBin, cwd, verbose);
41
42
  await this.createConfigFiles(projectName, cwd);
42
43
  await this.createDirs(cwd);
43
- await this.installDeps(pkgManagerBin, cwd);
44
- await this.commit(scmBin, initialCommit, cwd);
45
- await this.runDevCmds(pkgManagerBin, cwd);
44
+ await this.installDeps(pkgManagerBin, cwd, verbose);
45
+ await this.commit(scmBin, initialCommit, cwd, verbose);
46
+ await this.runDevCmds(pkgManagerBin, cwd, verbose);
46
47
  this.logger.info('Done ! Project ready ! ✅ 🚀');
47
48
  }
48
49
  async assertBinPresence(bin) {
@@ -56,7 +57,7 @@ let CreateProjectClientMain = class CreateProjectClientMain {
56
57
  throw new IllegalArgumentError(`'${bin}' seems missing. Is it installed on your machine ?`);
57
58
  }
58
59
  }
59
- async commit(scmBin, initialCommit, cwd) {
60
+ async commit(scmBin, initialCommit, cwd, verbose) {
60
61
  this.logger.info('Committing');
61
62
  const cmdArgs = [
62
63
  ['branch', '-M', 'master'],
@@ -66,7 +67,7 @@ let CreateProjectClientMain = class CreateProjectClientMain {
66
67
  for await (const args of cmdArgs) {
67
68
  await this.shellCommandExecutor.exec({
68
69
  bin: scmBin,
69
- opts: { args, cwd },
70
+ opts: { args, cwd, streamData: verbose },
70
71
  });
71
72
  }
72
73
  }
@@ -90,30 +91,30 @@ let CreateProjectClientMain = class CreateProjectClientMain {
90
91
  this.logger.info('Creating root dir : %s', cwd);
91
92
  await this.fsManager.mkdir(cwd, { recursive: true });
92
93
  }
93
- async initRepository(scmBin, cwd) {
94
+ async initRepository(scmBin, cwd, verbose) {
94
95
  const cmd = 'init';
95
96
  this.logger.info('Initializing repository : %s %s', scmBin, cmd);
96
97
  await this.shellCommandExecutor.exec({
97
98
  bin: scmBin,
98
- opts: { args: [cmd], cwd },
99
+ opts: { args: [cmd], cwd, streamData: verbose },
99
100
  });
100
101
  }
101
- async installDeps(pkgManagerBin, cwd) {
102
+ async installDeps(pkgManagerBin, cwd, verbose) {
102
103
  const cmd = 'install';
103
104
  this.logger.info('Installing dependencies : %s %s', pkgManagerBin, cmd);
104
105
  await this.shellCommandExecutor.exec({
105
106
  bin: pkgManagerBin,
106
- opts: { args: [cmd], cwd },
107
+ opts: { args: [cmd], cwd, streamData: verbose },
107
108
  });
108
109
  }
109
- async runDevCmds(pkgManagerBin, cwd) {
110
+ async runDevCmds(pkgManagerBin, cwd, verbose) {
110
111
  const cmd = 'run';
111
112
  const scripts = ['lint', 'test'];
112
113
  for await (const script of scripts) {
113
114
  this.logger.info('Running dev command : %s %s %s', pkgManagerBin, cmd, script);
114
115
  await this.shellCommandExecutor.exec({
115
116
  bin: pkgManagerBin,
116
- opts: { args: [cmd, script], cwd },
117
+ opts: { args: [cmd, script], cwd, streamData: verbose },
117
118
  });
118
119
  }
119
120
  }
@@ -170,6 +171,12 @@ export const CreateProjectUCD = {
170
171
  .setDefaultValue('git')
171
172
  .setExamples(['git']),
172
173
  },
174
+ verbose: {
175
+ cardinality: {
176
+ min: 0,
177
+ },
178
+ type: new TBoolean().setDefaultValue(false),
179
+ },
173
180
  },
174
181
  },
175
182
  },
@@ -57,6 +57,7 @@ import type { SSHPrivateKey } from './final/TSSHPrivateKey.js';
57
57
  import type { SSHPublicKey } from './final/TSSHPublicKey.js';
58
58
  import type { Time } from './final/TTime.js';
59
59
  import type { Timestamp } from './final/TTimestamp.js';
60
+ import type { TransportType } from './final/TTransportType.js';
60
61
  import type { UIntDuration } from './final/TUIntDuration.js';
61
62
  import type { UIntQuantity } from './final/TUIntQuantity.js';
62
63
  import type { URL } from './final/TURL.js';
@@ -66,5 +67,5 @@ import type { UUID } from './final/TUUID.js';
66
67
  import type { Year } from './final/TYear.js';
67
68
  import type { YesNo } from './final/TYesNo.js';
68
69
  type Primitive = string | number | boolean;
69
- export type DataType = Primitive | Address | Amount | ApiKey | BarCode | CSS | Color | ColorRGBA | CompanyName | CountryISO3166Alpha2 | CurrencyISO4217 | DateISO8601 | DateTimeFormat | DirPath | DomainName | Email | EmbeddedObject | Emoji | EncryptionKey | ErrorMessage | ExternalServiceId | File | FileExtension | FileMimeType | FileName | FilePath | FreeTextLong | FreeTextShort | Geolocation | GitSSHURL | HTML | HTTPContentType | HTTPMethod | HTTPStatusNumber | HostAddress | HostPort | IPv4 | IPv6 | JSONString | JWT | JavaScript | JobTitle | Markdown | NumIndex | Password | Percentage | PersonFirstname | PersonFullname | PersonInitials | PersonLastname | QRCode | SQLQuery | SSHPrivateKey | SSHPublicKey | SearchQuery | SemVerVersion | ShellCommand | Slug | Time | Timestamp | UIntDuration | UIntQuantity | URL | URLPath | UUID | Username | Year | YesNo;
70
+ export type DataType = Primitive | Address | Amount | ApiKey | BarCode | CSS | Color | ColorRGBA | CompanyName | CountryISO3166Alpha2 | CurrencyISO4217 | DateISO8601 | DateTimeFormat | DirPath | DomainName | Email | EmbeddedObject | Emoji | EncryptionKey | ErrorMessage | ExternalServiceId | File | FileExtension | FileMimeType | FileName | FilePath | FreeTextLong | FreeTextShort | Geolocation | GitSSHURL | HTML | HTTPContentType | HTTPMethod | HTTPStatusNumber | HostAddress | HostPort | IPv4 | IPv6 | JSONString | JWT | JavaScript | JobTitle | Markdown | NumIndex | Password | Percentage | PersonFirstname | PersonFullname | PersonInitials | PersonLastname | QRCode | SQLQuery | SSHPrivateKey | SSHPublicKey | SearchQuery | SemVerVersion | ShellCommand | Slug | Time | Timestamp | TransportType | UIntDuration | UIntQuantity | URL | URLPath | UUID | Username | Year | YesNo;
70
71
  export {};
@@ -58,6 +58,7 @@ export const DataTypes = [
58
58
  'Slug',
59
59
  'Time',
60
60
  'Timestamp',
61
+ 'TransportType',
61
62
  'UIntDuration',
62
63
  'UIntQuantity',
63
64
  'URL',
@@ -0,0 +1,8 @@
1
+ import type { TName } from '../base/TBase.js';
2
+ import { TString } from '../base/TString.js';
3
+ export type TransportType = 'standard' | 'stream';
4
+ export declare class TTransportType extends TString<TransportType, 'TransportType'> {
5
+ constructor();
6
+ tName(): TName;
7
+ example(): TransportType;
8
+ }
@@ -0,0 +1,16 @@
1
+ import { TString } from '../base/TString.js';
2
+ export class TTransportType extends TString {
3
+ constructor() {
4
+ super();
5
+ this.setOptions([
6
+ { label: 'standard', value: 'standard' },
7
+ { label: 'stream', value: 'stream' },
8
+ ]);
9
+ }
10
+ tName() {
11
+ return 'TransportType';
12
+ }
13
+ example() {
14
+ return 'standard';
15
+ }
16
+ }
@@ -66,6 +66,7 @@ export { type SSHPrivateKey, TSSHPrivateKey } from './final/TSSHPrivateKey.js';
66
66
  export { type SSHPublicKey, TSSHPublicKey } from './final/TSSHPublicKey.js';
67
67
  export { type Time, TTime } from './final/TTime.js';
68
68
  export { type Timestamp, TTimestamp } from './final/TTimestamp.js';
69
+ export { type TransportType, TTransportType } from './final/TTransportType.js';
69
70
  export { TUIntDuration, type UIntDuration } from './final/TUIntDuration.js';
70
71
  export { TUIntQuantity, type UIntQuantity } from './final/TUIntQuantity.js';
71
72
  export { TURL, type URL } from './final/TURL.js';
@@ -65,6 +65,7 @@ export { TSSHPrivateKey } from './final/TSSHPrivateKey.js';
65
65
  export { TSSHPublicKey } from './final/TSSHPublicKey.js';
66
66
  export { TTime } from './final/TTime.js';
67
67
  export { TTimestamp } from './final/TTimestamp.js';
68
+ export { TTransportType } from './final/TTransportType.js';
68
69
  export { TUIntDuration } from './final/TUIntDuration.js';
69
70
  export { TUIntQuantity } from './final/TUIntQuantity.js';
70
71
  export { TURL } from './final/TURL.js';
@@ -0,0 +1,2 @@
1
+ import type { ErrorMessage, HTTPStatusNumber } from '../dt/index.js';
2
+ export declare function throwCustomError(message: ErrorMessage, status: HTTPStatusNumber): never;
@@ -0,0 +1,19 @@
1
+ import { ForbiddenError } from './ForbiddenError.js';
2
+ import { IllegalArgumentError } from './IllegalArgumentError.js';
3
+ import { InternalServerError } from './InternalServerError.js';
4
+ import { NotFoundError } from './NotFoundError.js';
5
+ import { UnauthorizedError } from './UnauthorizedError.js';
6
+ const ERROR_HTTP_STATUS_MAP = new Map([
7
+ [400, IllegalArgumentError],
8
+ [401, UnauthorizedError],
9
+ [403, ForbiddenError],
10
+ [404, NotFoundError],
11
+ [500, InternalServerError],
12
+ ]);
13
+ export function throwCustomError(message, status) {
14
+ const clazz = ERROR_HTTP_STATUS_MAP.get(status);
15
+ if (clazz) {
16
+ throw new clazz(message);
17
+ }
18
+ throw new InternalServerError(message);
19
+ }
@@ -1,6 +1,7 @@
1
1
  export { CustomError, type ServerError } from './CustomError.js';
2
2
  export { ForbiddenAsNotFoundError } from './ForbiddenAsNotFoundError.js';
3
3
  export { ForbiddenError } from './ForbiddenError.js';
4
+ export { throwCustomError } from './funcs.js';
4
5
  export { IllegalArgumentError } from './IllegalArgumentError.js';
5
6
  export { InternalServerError } from './InternalServerError.js';
6
7
  export { NotAvailableError } from './internal/NotAvailableError.js';
@@ -1,6 +1,7 @@
1
1
  export { CustomError } from './CustomError.js';
2
2
  export { ForbiddenAsNotFoundError } from './ForbiddenAsNotFoundError.js';
3
3
  export { ForbiddenError } from './ForbiddenError.js';
4
+ export { throwCustomError } from './funcs.js';
4
5
  export { IllegalArgumentError } from './IllegalArgumentError.js';
5
6
  export { InternalServerError } from './InternalServerError.js';
6
7
  export { NotAvailableError } from './internal/NotAvailableError.js';
@@ -7,10 +7,12 @@ export * from './icon/index.js';
7
7
  export * from './product/index.js';
8
8
  export * from './std/impl/ConsoleLogger.js';
9
9
  export * from './std/impl/EnvSettingsManager.js';
10
+ export * from './std/impl/FakeClockManager.js';
10
11
  export * from './std/impl/FakeEmailManager.js';
11
12
  export * from './std/impl/FakeFSManager.js';
12
13
  export * from './std/impl/FakeHTTPAPICallExecutor.js';
13
14
  export * from './std/impl/FakeJobManager.js';
15
+ export * from './std/impl/FakeLLMManager.js';
14
16
  export * from './std/impl/FetchHTTPAPICallExecutor.js';
15
17
  export * from './std/impl/MistralAILLMManager.js';
16
18
  export * from './std/impl/NoopHTTPAPICallExecutorAgentBuilder.js';
package/dist/esm/index.js CHANGED
@@ -8,10 +8,12 @@ export * from './icon/index.js';
8
8
  export * from './product/index.js';
9
9
  export * from './std/impl/ConsoleLogger.js';
10
10
  export * from './std/impl/EnvSettingsManager.js';
11
+ export * from './std/impl/FakeClockManager.js';
11
12
  export * from './std/impl/FakeEmailManager.js';
12
13
  export * from './std/impl/FakeFSManager.js';
13
14
  export * from './std/impl/FakeHTTPAPICallExecutor.js';
14
15
  export * from './std/impl/FakeJobManager.js';
16
+ export * from './std/impl/FakeLLMManager.js';
15
17
  export * from './std/impl/FetchHTTPAPICallExecutor.js';
16
18
  export * from './std/impl/MistralAILLMManager.js';
17
19
  export * from './std/impl/NoopHTTPAPICallExecutorAgentBuilder.js';
@@ -16,16 +16,25 @@ export type HTTPAPICallExecutorFunc<Res> = (url: URL | URLString, info?: {
16
16
  body?: Awaited<ReturnType<HTTPRequestBuilder['exec']>>['body'];
17
17
  headers?: HTTPAPICallerHeaders;
18
18
  method?: HTTPMethod;
19
+ signal?: AbortController['signal'];
19
20
  }) => Promise<HTTPAPICallExecutorResponse<Res>>;
21
+ export interface HTTPAPICallExecutorResBody {
22
+ getReader(): {
23
+ read: () => Promise<{
24
+ done: boolean;
25
+ value: Uint8Array;
26
+ }>;
27
+ };
28
+ readable: boolean;
29
+ }
30
+ export interface HTTPAPICallExecutorResHeaders {
31
+ entries(): IterableIterator<[string, string]>;
32
+ get: (name: 'Content-Type') => HTTPContentType;
33
+ }
20
34
  export interface HTTPAPICallExecutorResponse<Res> {
21
35
  arrayBuffer(): Promise<Buffer>;
22
- body: {
23
- readable: boolean;
24
- };
25
- headers: {
26
- entries(): IterableIterator<[string, string]>;
27
- get: (name: 'Content-Type') => HTTPContentType;
28
- };
36
+ body: HTTPAPICallExecutorResBody | undefined;
37
+ headers: HTTPAPICallExecutorResHeaders;
29
38
  json: () => Promise<Res>;
30
39
  ok: boolean;
31
40
  redirected: boolean;
@@ -1,5 +1,5 @@
1
1
  import type { ApiKey, ErrorMessage, HTTPContentType, HTTPMethod, JWT, Password, URL, Username } from '../dt/index.js';
2
- import type { HTTPDataEnvelope } from '../utils/index.js';
2
+ import type { HTTPDataEnvelope, RegisterAbortFunc } from '../utils/index.js';
3
3
  import type { XMLManagerParseOpts } from './XMLManager.js';
4
4
  type AdditionalHeadersBuilder<AH> = () => Promise<AH>;
5
5
  type ErrBuilder<ResBad> = (response: ResBad) => Promise<ErrorMessage>;
@@ -30,6 +30,9 @@ export interface HTTPAPICallerInput<AH extends object | undefined, Req extends o
30
30
  additionalHeadersBuilder?: AdditionalHeadersBuilder<AH> | undefined;
31
31
  authorizationHeader?: HTTPAPICallerAuthorizationHeader | undefined;
32
32
  basicAuth?: HTTPAPICallerBasicAuth | undefined;
33
+ /**
34
+ * @default application/json
35
+ */
33
36
  contentType?: HTTPContentType;
34
37
  errBuilder: ErrBuilder<ResBad>;
35
38
  method: HTTPMethod;
@@ -38,10 +41,14 @@ export interface HTTPAPICallerInput<AH extends object | undefined, Req extends o
38
41
  * If not set, it will assume that `ResGood` and `O` are the same and thus return `ResGood` as is.
39
42
  */
40
43
  outputBuilder?: OutputBuilder<ResGood, O> | undefined;
44
+ registerAbort?: RegisterAbortFunc | undefined;
41
45
  req?: {
42
46
  builder: ReqBuilder<Req>;
43
47
  envelope: HTTPDataEnvelope;
44
48
  } | undefined;
49
+ stream?: {
50
+ onData: (res: O) => void;
51
+ } | undefined;
45
52
  unknownErrorMessage?: ErrorMessage | undefined;
46
53
  urlBuilder: URLBuilder;
47
54
  }
@@ -1,13 +1,19 @@
1
1
  import type { ApiKey, FreeTextLong } from '../dt/index.js';
2
+ import type { StreamConfig } from '../utils/index.js';
2
3
  export type LLMManagerModel = string;
3
4
  export type LLMManagerTemperature = number;
4
5
  export interface LLMManagerSendOpts {
5
6
  /**
6
- * By default, each implementation reads the auth from the settings. If provided here, it takes precedence over the settings value.
7
+ * By default, each implementation reads the auth from the settings.
8
+ * If provided here, it takes precedence over the settings value.
7
9
  */
8
10
  auth?: {
9
11
  apiKey?: ApiKey;
10
12
  };
13
+ /**
14
+ * Callbacks used when `stream` is `true`
15
+ */
16
+ stream?: StreamConfig<LLMManagerSendRes>;
11
17
  }
12
18
  export interface LLMManagerSendReq {
13
19
  messages: {
@@ -19,11 +25,22 @@ export interface LLMManagerSendReq {
19
25
  role: 'assistant' | 'developer' | 'system' | 'user';
20
26
  }[];
21
27
  model: LLMManagerModel;
22
- temperature?: LLMManagerTemperature;
28
+ stream?: boolean | undefined;
29
+ temperature?: LLMManagerTemperature | undefined;
23
30
  }
24
31
  export interface LLMManagerSendRes {
25
32
  choices: {
26
- message: {
33
+ /**
34
+ * Result chunk when stream is enabled
35
+ */
36
+ delta?: {
37
+ content: string;
38
+ };
39
+ finish_reason: 'content_filter' | 'length' | 'stop' | 'tool_calls' | null;
40
+ /**
41
+ * Full result stream is not enabled
42
+ */
43
+ message?: {
27
44
  content: string;
28
45
  };
29
46
  }[];
@@ -0,0 +1,6 @@
1
+ import type { DateISO8601 } from '../../dt/index.js';
2
+ import { StdDateClockManager } from './StdDateClockManager.js';
3
+ export declare const FAKE_CLOCK_MANAGER_NOW: DateISO8601;
4
+ export declare class FakeClockManager extends StdDateClockManager {
5
+ now(): Date;
6
+ }
@@ -0,0 +1,19 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { injectable } from 'inversify';
8
+ import { StdDateClockManager } from './StdDateClockManager.js';
9
+ // We set now as this specific value to make tests deterministic
10
+ export const FAKE_CLOCK_MANAGER_NOW = '2022-05-15T20:23:30.123Z';
11
+ let FakeClockManager = class FakeClockManager extends StdDateClockManager {
12
+ now() {
13
+ return new Date(Date.parse(FAKE_CLOCK_MANAGER_NOW));
14
+ }
15
+ };
16
+ FakeClockManager = __decorate([
17
+ injectable()
18
+ ], FakeClockManager);
19
+ export { FakeClockManager };
@@ -26,19 +26,27 @@ let FakeHTTPAPICallExecutor = class FakeHTTPAPICallExecutor {
26
26
  }
27
27
  const key = (typeof url === 'string' ? url : url.toString());
28
28
  const content = this.entries.get(key);
29
+ const body = {
30
+ getReader: () => ({
31
+ read: async () => ({
32
+ done: true,
33
+ value: new Uint8Array(),
34
+ }),
35
+ }),
36
+ readable: true,
37
+ };
38
+ const headers = {
39
+ entries: () => [
40
+ ['Content-Type', 'application/json'],
41
+ ].values(),
42
+ get: (_) => 'application/json',
43
+ };
29
44
  if (!content) {
30
45
  const message = `Endpoint ${url} not defined in FakeHTTPAPICallExecutor.entries`;
31
46
  return {
32
47
  arrayBuffer: async () => Buffer.from(''),
33
- body: {
34
- readable: true,
35
- },
36
- headers: {
37
- entries: () => [
38
- ['Content-Type', 'application/json'],
39
- ].values(),
40
- get: (_) => 'application/json',
41
- },
48
+ body,
49
+ headers,
42
50
  json: async () => ({ message }),
43
51
  ok: false,
44
52
  redirected: false,
@@ -48,15 +56,8 @@ let FakeHTTPAPICallExecutor = class FakeHTTPAPICallExecutor {
48
56
  }
49
57
  return {
50
58
  arrayBuffer: async () => Buffer.from(content),
51
- body: {
52
- readable: true,
53
- },
54
- headers: {
55
- entries: () => [
56
- ['Content-Type', 'application/json'],
57
- ].values(),
58
- get: (_) => 'application/json',
59
- },
59
+ body,
60
+ headers,
60
61
  json: async () => JSON.parse(content),
61
62
  ok: true,
62
63
  redirected: false,
@@ -0,0 +1,4 @@
1
+ import type { LLMManager, LLMManagerSendOpts, LLMManagerSendReq, LLMManagerSendRes } from '../LLMManager.js';
2
+ export declare class FakeLLMManager implements LLMManager {
3
+ send(req: LLMManagerSendReq, opts?: LLMManagerSendOpts): Promise<LLMManagerSendRes>;
4
+ }
@@ -0,0 +1,40 @@
1
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
2
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
3
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
4
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
5
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
6
+ };
7
+ import { injectable } from 'inversify';
8
+ let FakeLLMManager = class FakeLLMManager {
9
+ async send(req, opts) {
10
+ const content = `I'm not able to process your request : ${JSON.stringify(req)}`;
11
+ if (req.stream) {
12
+ await opts?.stream?.onData({
13
+ choices: [
14
+ {
15
+ delta: {
16
+ content,
17
+ },
18
+ finish_reason: 'stop',
19
+ },
20
+ ],
21
+ });
22
+ await opts?.stream?.onDone();
23
+ return { choices: [] };
24
+ }
25
+ return {
26
+ choices: [
27
+ {
28
+ finish_reason: 'stop',
29
+ message: {
30
+ content,
31
+ },
32
+ },
33
+ ],
34
+ };
35
+ }
36
+ };
37
+ FakeLLMManager = __decorate([
38
+ injectable()
39
+ ], FakeLLMManager);
40
+ export { FakeLLMManager };
@@ -36,6 +36,9 @@ let MistralAILLMManager = class MistralAILLMManager {
36
36
  if ('message' in error) {
37
37
  return error.message;
38
38
  }
39
+ if (typeof error.detail === 'string') {
40
+ return error.detail;
41
+ }
39
42
  return error.detail.map((d) => d.msg).join('\n');
40
43
  },
41
44
  method: 'POST',
@@ -43,6 +46,15 @@ let MistralAILLMManager = class MistralAILLMManager {
43
46
  builder: async () => req,
44
47
  envelope: 'json',
45
48
  },
49
+ stream: {
50
+ onData: (res) => {
51
+ opts?.stream?.onData?.(res);
52
+ // Beware : this won't work if/when we accept multiple choices in the request
53
+ if (res.choices[0]?.finish_reason) {
54
+ opts?.stream?.onDone();
55
+ }
56
+ },
57
+ },
46
58
  urlBuilder: async () => `${MistralAILLMManager_1.BASE_URL}/chat/completions`,
47
59
  });
48
60
  }
@@ -1,7 +1,11 @@
1
1
  import type { URL } from '../../dt/index.js';
2
2
  import type { HTTPAPICaller } from '../HTTPAPICaller.js';
3
- import type { LLMManager, LLMManagerSendReq, LLMManagerSendRes } from '../LLMManager.js';
3
+ import type { LLMManager, LLMManagerSendOpts, LLMManagerSendReq, LLMManagerSendRes } from '../LLMManager.js';
4
4
  import type { Configurable, Settings, SettingsManager } from '../SettingsManager.js';
5
+ interface OllamaGenerateRes {
6
+ done: boolean;
7
+ response: string;
8
+ }
5
9
  /**
6
10
  * Unlike the "commercial" APIs, Ollama does not secure the API with an API key
7
11
  * @see https://github.com/ollama/ollama/issues/849
@@ -15,6 +19,7 @@ export declare class OllamaLLMManager implements Configurable<S>, LLMManager {
15
19
  private settingsManager;
16
20
  constructor(httpAPICaller: HTTPAPICaller, settingsManager: SettingsManager<S>);
17
21
  s(): OllamaLLMManagerSettings;
18
- send(req: LLMManagerSendReq): Promise<LLMManagerSendRes>;
22
+ send(req: LLMManagerSendReq, opts?: LLMManagerSendOpts): Promise<LLMManagerSendRes>;
23
+ toRes(stream: LLMManagerSendReq['stream'], res: OllamaGenerateRes): LLMManagerSendRes;
19
24
  }
20
25
  export {};