libretto 0.2.3 → 0.2.5
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 +78 -184
- package/dist/cli/cli.js +8 -2
- package/dist/cli/commands/browser.js +26 -3
- package/dist/cli/commands/execution.js +50 -11
- package/dist/cli/commands/init.js +95 -0
- package/dist/cli/core/browser.js +131 -6
- package/dist/cli/core/context.js +5 -0
- package/dist/cli/core/session.js +13 -13
- package/dist/cli/workers/run-integration-runtime.js +64 -59
- package/dist/cli/workers/run-integration-worker-protocol.js +12 -0
- package/dist/cli/workers/run-integration-worker.js +13 -30
- package/dist/index.cjs +5 -12
- package/dist/index.d.cts +4 -2
- package/dist/index.d.ts +4 -2
- package/dist/index.js +5 -15
- package/dist/shared/debug/index.cjs +4 -6
- package/dist/shared/debug/index.d.cts +1 -2
- package/dist/shared/debug/index.d.ts +1 -2
- package/dist/shared/debug/index.js +3 -8
- package/dist/shared/debug/pause.cjs +58 -24
- package/dist/shared/debug/pause.d.cts +13 -20
- package/dist/shared/debug/pause.d.ts +13 -20
- package/dist/shared/debug/pause.js +46 -21
- package/dist/shared/llm/ai-sdk-adapter.cjs +67 -0
- package/dist/shared/llm/ai-sdk-adapter.d.cts +22 -0
- package/dist/shared/llm/ai-sdk-adapter.d.ts +22 -0
- package/dist/shared/llm/ai-sdk-adapter.js +43 -0
- package/dist/shared/llm/index.cjs +5 -2
- package/dist/shared/llm/index.d.cts +2 -0
- package/dist/shared/llm/index.d.ts +2 -0
- package/dist/shared/llm/index.js +3 -1
- package/dist/shared/llm/types.d.cts +32 -0
- package/dist/shared/llm/types.d.ts +32 -0
- package/dist/shared/run/api.cjs +0 -7
- package/dist/shared/run/api.d.cts +0 -1
- package/dist/shared/run/api.d.ts +0 -1
- package/dist/shared/run/api.js +0 -8
- package/dist/shared/workflow/workflow.d.cts +11 -24
- package/dist/shared/workflow/workflow.d.ts +11 -24
- package/package.json +4 -10
- package/skill/SKILL.md +18 -5
- package/skill/code-generation-rules.md +7 -10
package/dist/index.js
CHANGED
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
prettyConsoleSink,
|
|
5
5
|
jsonlConsoleSink
|
|
6
6
|
} from "./shared/logger/sinks.js";
|
|
7
|
+
import { createLLMClientFromModel } from "./shared/llm/ai-sdk-adapter.js";
|
|
7
8
|
import {
|
|
8
9
|
SESSION_STATE_VERSION,
|
|
9
10
|
SessionStatusSchema,
|
|
@@ -25,11 +26,7 @@ import {
|
|
|
25
26
|
downloadViaClick,
|
|
26
27
|
downloadAndSave
|
|
27
28
|
} from "./runtime/download/download.js";
|
|
28
|
-
import {
|
|
29
|
-
debugPause,
|
|
30
|
-
DebugPauseSignal,
|
|
31
|
-
isDebugPauseSignal
|
|
32
|
-
} from "./shared/debug/pause.js";
|
|
29
|
+
import { pause } from "./shared/debug/pause.js";
|
|
33
30
|
import {
|
|
34
31
|
isDebugMode,
|
|
35
32
|
isDryRun,
|
|
@@ -52,10 +49,7 @@ import {
|
|
|
52
49
|
clearHighlights
|
|
53
50
|
} from "./shared/visualization/highlight.js";
|
|
54
51
|
import {
|
|
55
|
-
launchBrowser
|
|
56
|
-
debugPause as debugPause2,
|
|
57
|
-
DebugPauseSignal as DebugPauseSignal2,
|
|
58
|
-
isDebugPauseSignal as isDebugPauseSignal2
|
|
52
|
+
launchBrowser
|
|
59
53
|
} from "./shared/run/api.js";
|
|
60
54
|
import {
|
|
61
55
|
LibrettoWorkflow,
|
|
@@ -63,18 +57,16 @@ import {
|
|
|
63
57
|
workflow
|
|
64
58
|
} from "./shared/workflow/workflow.js";
|
|
65
59
|
export {
|
|
66
|
-
DebugPauseSignal,
|
|
67
60
|
LIBRETTO_WORKFLOW_BRAND,
|
|
68
61
|
LibrettoWorkflow,
|
|
69
62
|
Logger,
|
|
70
|
-
DebugPauseSignal2 as RunDebugPauseSignal,
|
|
71
63
|
SESSION_STATE_VERSION,
|
|
72
64
|
SessionStateFileSchema,
|
|
73
65
|
SessionStatusSchema,
|
|
74
66
|
attemptWithRecovery,
|
|
75
67
|
clearHighlights,
|
|
76
68
|
createFileLogSink,
|
|
77
|
-
|
|
69
|
+
createLLMClientFromModel,
|
|
78
70
|
defaultLogger,
|
|
79
71
|
detectSubmissionError,
|
|
80
72
|
downloadAndSave,
|
|
@@ -89,17 +81,15 @@ export {
|
|
|
89
81
|
instrumentContext,
|
|
90
82
|
instrumentPage,
|
|
91
83
|
isDebugMode,
|
|
92
|
-
isDebugPauseSignal,
|
|
93
84
|
isDryRun,
|
|
94
|
-
isDebugPauseSignal2 as isRunDebugPauseSignal,
|
|
95
85
|
jsonlConsoleSink,
|
|
96
86
|
launchBrowser,
|
|
97
87
|
moveGhostCursor,
|
|
98
88
|
pageRequest,
|
|
99
89
|
parseSessionStateContent,
|
|
100
90
|
parseSessionStateData,
|
|
91
|
+
pause,
|
|
101
92
|
prettyConsoleSink,
|
|
102
|
-
debugPause2 as runDebugPause,
|
|
103
93
|
serializeSessionState,
|
|
104
94
|
shouldPauseBeforeMutation,
|
|
105
95
|
showHighlight,
|
|
@@ -18,15 +18,13 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var debug_exports = {};
|
|
20
20
|
__export(debug_exports, {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
isDebugPauseSignal: () => import_pause.isDebugPauseSignal
|
|
21
|
+
pause: () => import_pause.pause,
|
|
22
|
+
setSessionForPause: () => import_pause.setSessionForPause
|
|
24
23
|
});
|
|
25
24
|
module.exports = __toCommonJS(debug_exports);
|
|
26
25
|
var import_pause = require("./pause.js");
|
|
27
26
|
// Annotate the CommonJS export names for ESM import in node:
|
|
28
27
|
0 && (module.exports = {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
isDebugPauseSignal
|
|
28
|
+
pause,
|
|
29
|
+
setSessionForPause
|
|
32
30
|
});
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export {
|
|
2
|
-
import 'playwright';
|
|
1
|
+
export { pause, setSessionForPause } from './pause.cjs';
|
|
@@ -1,2 +1 @@
|
|
|
1
|
-
export {
|
|
2
|
-
import 'playwright';
|
|
1
|
+
export { pause, setSessionForPause } from './pause.js';
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
2
3
|
var __defProp = Object.defineProperty;
|
|
3
4
|
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
5
|
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
5
7
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
8
|
var __export = (target, all) => {
|
|
7
9
|
for (var name in all)
|
|
@@ -15,42 +17,74 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
15
17
|
}
|
|
16
18
|
return to;
|
|
17
19
|
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
18
28
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
29
|
var pause_exports = {};
|
|
20
30
|
__export(pause_exports, {
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
isDebugPauseSignal: () => isDebugPauseSignal
|
|
31
|
+
pause: () => pause,
|
|
32
|
+
setSessionForPause: () => setSessionForPause
|
|
24
33
|
});
|
|
25
34
|
module.exports = __toCommonJS(pause_exports);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
35
|
+
var import_node_fs = require("node:fs");
|
|
36
|
+
var import_promises = require("node:fs/promises");
|
|
37
|
+
let _sessionName;
|
|
38
|
+
function setSessionForPause(session) {
|
|
39
|
+
_sessionName = session;
|
|
40
|
+
}
|
|
41
|
+
function getSessionFromProcessArgs() {
|
|
42
|
+
const rawPayload = process.argv[2];
|
|
43
|
+
if (!rawPayload) return void 0;
|
|
44
|
+
try {
|
|
45
|
+
const parsed = JSON.parse(rawPayload);
|
|
46
|
+
return typeof parsed.session === "string" ? parsed.session : void 0;
|
|
47
|
+
} catch {
|
|
48
|
+
return void 0;
|
|
32
49
|
}
|
|
33
50
|
}
|
|
34
|
-
function
|
|
35
|
-
|
|
36
|
-
const candidate = error;
|
|
37
|
-
if (candidate.name !== "DebugPauseSignal") return false;
|
|
38
|
-
return typeof candidate.details?.sessionName === "string" && typeof candidate.details?.pausedAt === "string" && typeof candidate.details?.url === "string";
|
|
51
|
+
function resolveSession() {
|
|
52
|
+
return _sessionName ?? getSessionFromProcessArgs();
|
|
39
53
|
}
|
|
40
|
-
async function
|
|
41
|
-
|
|
54
|
+
async function pause() {
|
|
55
|
+
if (process.env.NODE_ENV === "production") {
|
|
56
|
+
return;
|
|
57
|
+
}
|
|
58
|
+
const session = resolveSession();
|
|
59
|
+
if (!session) {
|
|
60
|
+
return;
|
|
61
|
+
}
|
|
62
|
+
const { getPauseSignalPaths, removeSignalIfExists } = await import("../../cli/core/pause-signals.js");
|
|
63
|
+
const { getSessionDir } = await import("../../cli/core/context.js");
|
|
64
|
+
const signalPaths = getPauseSignalPaths(session);
|
|
65
|
+
const { pausedSignalPath, resumeSignalPath } = signalPaths;
|
|
66
|
+
await (0, import_promises.mkdir)(getSessionDir(session), { recursive: true });
|
|
67
|
+
await removeSignalIfExists(resumeSignalPath);
|
|
42
68
|
const details = {
|
|
43
|
-
sessionName:
|
|
69
|
+
sessionName: session,
|
|
44
70
|
pausedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
45
|
-
url
|
|
71
|
+
url: "unknown"
|
|
46
72
|
};
|
|
47
|
-
|
|
48
|
-
console.log(
|
|
49
|
-
|
|
73
|
+
await (0, import_promises.writeFile)(pausedSignalPath, JSON.stringify(details, null, 2), "utf8");
|
|
74
|
+
console.log(`[pause] Paused (session: ${session})`);
|
|
75
|
+
console.log("[pause] Waiting for resume signal...");
|
|
76
|
+
const RESUME_POLL_INTERVAL_MS = 250;
|
|
77
|
+
while (!(0, import_node_fs.existsSync)(resumeSignalPath)) {
|
|
78
|
+
await new Promise(
|
|
79
|
+
(resolve) => setTimeout(resolve, RESUME_POLL_INTERVAL_MS)
|
|
80
|
+
);
|
|
81
|
+
}
|
|
82
|
+
await removeSignalIfExists(resumeSignalPath);
|
|
83
|
+
await removeSignalIfExists(pausedSignalPath);
|
|
84
|
+
console.log("[pause] Resume signal received. Continuing workflow...");
|
|
50
85
|
}
|
|
51
86
|
// Annotate the CommonJS export names for ESM import in node:
|
|
52
87
|
0 && (module.exports = {
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
isDebugPauseSignal
|
|
88
|
+
pause,
|
|
89
|
+
setSessionForPause
|
|
56
90
|
});
|
|
@@ -1,23 +1,16 @@
|
|
|
1
|
-
import { Page } from 'playwright';
|
|
2
|
-
|
|
3
|
-
type DebugPauseContext = {
|
|
4
|
-
page: Page;
|
|
5
|
-
session: string;
|
|
6
|
-
};
|
|
7
|
-
type DebugPauseDetails = {
|
|
8
|
-
sessionName: string;
|
|
9
|
-
pausedAt: string;
|
|
10
|
-
url: string;
|
|
11
|
-
};
|
|
12
|
-
declare class DebugPauseSignal extends Error {
|
|
13
|
-
readonly details: DebugPauseDetails;
|
|
14
|
-
constructor(details: DebugPauseDetails);
|
|
15
|
-
}
|
|
16
|
-
declare function isDebugPauseSignal(error: unknown): error is DebugPauseSignal;
|
|
17
1
|
/**
|
|
18
|
-
*
|
|
19
|
-
|
|
2
|
+
* Called by the CLI runtime to make the session name available to `pause()`.
|
|
3
|
+
*/
|
|
4
|
+
declare function setSessionForPause(session: string): void;
|
|
5
|
+
/**
|
|
6
|
+
* Standalone pause function.
|
|
7
|
+
*
|
|
8
|
+
* - In production (`NODE_ENV === "production"`), returns immediately (no-op).
|
|
9
|
+
* - Otherwise, writes a `.paused` signal file and polls for a `.resume` signal,
|
|
10
|
+
* using the same file-based mechanism as the CLI runner.
|
|
11
|
+
*
|
|
12
|
+
* Import directly: `import { pause } from "libretto";`
|
|
20
13
|
*/
|
|
21
|
-
declare function
|
|
14
|
+
declare function pause(): Promise<void>;
|
|
22
15
|
|
|
23
|
-
export {
|
|
16
|
+
export { pause, setSessionForPause };
|
|
@@ -1,23 +1,16 @@
|
|
|
1
|
-
import { Page } from 'playwright';
|
|
2
|
-
|
|
3
|
-
type DebugPauseContext = {
|
|
4
|
-
page: Page;
|
|
5
|
-
session: string;
|
|
6
|
-
};
|
|
7
|
-
type DebugPauseDetails = {
|
|
8
|
-
sessionName: string;
|
|
9
|
-
pausedAt: string;
|
|
10
|
-
url: string;
|
|
11
|
-
};
|
|
12
|
-
declare class DebugPauseSignal extends Error {
|
|
13
|
-
readonly details: DebugPauseDetails;
|
|
14
|
-
constructor(details: DebugPauseDetails);
|
|
15
|
-
}
|
|
16
|
-
declare function isDebugPauseSignal(error: unknown): error is DebugPauseSignal;
|
|
17
1
|
/**
|
|
18
|
-
*
|
|
19
|
-
|
|
2
|
+
* Called by the CLI runtime to make the session name available to `pause()`.
|
|
3
|
+
*/
|
|
4
|
+
declare function setSessionForPause(session: string): void;
|
|
5
|
+
/**
|
|
6
|
+
* Standalone pause function.
|
|
7
|
+
*
|
|
8
|
+
* - In production (`NODE_ENV === "production"`), returns immediately (no-op).
|
|
9
|
+
* - Otherwise, writes a `.paused` signal file and polls for a `.resume` signal,
|
|
10
|
+
* using the same file-based mechanism as the CLI runner.
|
|
11
|
+
*
|
|
12
|
+
* Import directly: `import { pause } from "libretto";`
|
|
20
13
|
*/
|
|
21
|
-
declare function
|
|
14
|
+
declare function pause(): Promise<void>;
|
|
22
15
|
|
|
23
|
-
export {
|
|
16
|
+
export { pause, setSessionForPause };
|
|
@@ -1,30 +1,55 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { mkdir, writeFile } from "node:fs/promises";
|
|
3
|
+
let _sessionName;
|
|
4
|
+
function setSessionForPause(session) {
|
|
5
|
+
_sessionName = session;
|
|
6
|
+
}
|
|
7
|
+
function getSessionFromProcessArgs() {
|
|
8
|
+
const rawPayload = process.argv[2];
|
|
9
|
+
if (!rawPayload) return void 0;
|
|
10
|
+
try {
|
|
11
|
+
const parsed = JSON.parse(rawPayload);
|
|
12
|
+
return typeof parsed.session === "string" ? parsed.session : void 0;
|
|
13
|
+
} catch {
|
|
14
|
+
return void 0;
|
|
7
15
|
}
|
|
8
16
|
}
|
|
9
|
-
function
|
|
10
|
-
|
|
11
|
-
const candidate = error;
|
|
12
|
-
if (candidate.name !== "DebugPauseSignal") return false;
|
|
13
|
-
return typeof candidate.details?.sessionName === "string" && typeof candidate.details?.pausedAt === "string" && typeof candidate.details?.url === "string";
|
|
17
|
+
function resolveSession() {
|
|
18
|
+
return _sessionName ?? getSessionFromProcessArgs();
|
|
14
19
|
}
|
|
15
|
-
async function
|
|
16
|
-
|
|
20
|
+
async function pause() {
|
|
21
|
+
if (process.env.NODE_ENV === "production") {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
const session = resolveSession();
|
|
25
|
+
if (!session) {
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
const { getPauseSignalPaths, removeSignalIfExists } = await import("../../cli/core/pause-signals.js");
|
|
29
|
+
const { getSessionDir } = await import("../../cli/core/context.js");
|
|
30
|
+
const signalPaths = getPauseSignalPaths(session);
|
|
31
|
+
const { pausedSignalPath, resumeSignalPath } = signalPaths;
|
|
32
|
+
await mkdir(getSessionDir(session), { recursive: true });
|
|
33
|
+
await removeSignalIfExists(resumeSignalPath);
|
|
17
34
|
const details = {
|
|
18
|
-
sessionName:
|
|
35
|
+
sessionName: session,
|
|
19
36
|
pausedAt: (/* @__PURE__ */ new Date()).toISOString(),
|
|
20
|
-
url
|
|
37
|
+
url: "unknown"
|
|
21
38
|
};
|
|
22
|
-
|
|
23
|
-
console.log(
|
|
24
|
-
|
|
39
|
+
await writeFile(pausedSignalPath, JSON.stringify(details, null, 2), "utf8");
|
|
40
|
+
console.log(`[pause] Paused (session: ${session})`);
|
|
41
|
+
console.log("[pause] Waiting for resume signal...");
|
|
42
|
+
const RESUME_POLL_INTERVAL_MS = 250;
|
|
43
|
+
while (!existsSync(resumeSignalPath)) {
|
|
44
|
+
await new Promise(
|
|
45
|
+
(resolve) => setTimeout(resolve, RESUME_POLL_INTERVAL_MS)
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
await removeSignalIfExists(resumeSignalPath);
|
|
49
|
+
await removeSignalIfExists(pausedSignalPath);
|
|
50
|
+
console.log("[pause] Resume signal received. Continuing workflow...");
|
|
25
51
|
}
|
|
26
52
|
export {
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
isDebugPauseSignal
|
|
53
|
+
pause,
|
|
54
|
+
setSessionForPause
|
|
30
55
|
};
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
var ai_sdk_adapter_exports = {};
|
|
20
|
+
__export(ai_sdk_adapter_exports, {
|
|
21
|
+
createLLMClientFromModel: () => createLLMClientFromModel
|
|
22
|
+
});
|
|
23
|
+
module.exports = __toCommonJS(ai_sdk_adapter_exports);
|
|
24
|
+
var import_ai = require("ai");
|
|
25
|
+
function createLLMClientFromModel(model) {
|
|
26
|
+
return {
|
|
27
|
+
async generateObject(opts) {
|
|
28
|
+
const { object } = await (0, import_ai.generateObject)({
|
|
29
|
+
model,
|
|
30
|
+
schema: opts.schema,
|
|
31
|
+
prompt: opts.prompt,
|
|
32
|
+
temperature: opts.temperature ?? 0
|
|
33
|
+
});
|
|
34
|
+
return object;
|
|
35
|
+
},
|
|
36
|
+
async generateObjectFromMessages(opts) {
|
|
37
|
+
const messages = opts.messages.map((msg) => {
|
|
38
|
+
if (typeof msg.content === "string") {
|
|
39
|
+
return { role: msg.role, content: msg.content };
|
|
40
|
+
}
|
|
41
|
+
if (msg.role === "assistant") {
|
|
42
|
+
return {
|
|
43
|
+
role: "assistant",
|
|
44
|
+
content: msg.content.filter((part) => part.type === "text").map((part) => ({ type: "text", text: part.text }))
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
return {
|
|
48
|
+
role: "user",
|
|
49
|
+
content: msg.content.map(
|
|
50
|
+
(part) => part.type === "text" ? { type: "text", text: part.text } : { type: "image", image: part.image }
|
|
51
|
+
)
|
|
52
|
+
};
|
|
53
|
+
});
|
|
54
|
+
const { object } = await (0, import_ai.generateObject)({
|
|
55
|
+
model,
|
|
56
|
+
schema: opts.schema,
|
|
57
|
+
messages,
|
|
58
|
+
temperature: opts.temperature ?? 0
|
|
59
|
+
});
|
|
60
|
+
return object;
|
|
61
|
+
}
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
65
|
+
0 && (module.exports = {
|
|
66
|
+
createLLMClientFromModel
|
|
67
|
+
});
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { LanguageModel } from 'ai';
|
|
2
|
+
import { LLMClient } from './types.cjs';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a libretto LLMClient from a Vercel AI SDK LanguageModel.
|
|
7
|
+
*
|
|
8
|
+
* This eliminates the need for consumers to write their own adapter
|
|
9
|
+
* when using @ai-sdk/openai, @ai-sdk/anthropic, @ai-sdk/google-vertex,
|
|
10
|
+
* or any other Vercel AI SDK-compatible provider.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { createLLMClientFromModel } from "libretto/llm";
|
|
15
|
+
* import { openai } from "@ai-sdk/openai";
|
|
16
|
+
*
|
|
17
|
+
* const llmClient = createLLMClientFromModel(openai("gpt-4o"));
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
declare function createLLMClientFromModel(model: LanguageModel): LLMClient;
|
|
21
|
+
|
|
22
|
+
export { createLLMClientFromModel };
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { LanguageModel } from 'ai';
|
|
2
|
+
import { LLMClient } from './types.js';
|
|
3
|
+
import 'zod';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* Creates a libretto LLMClient from a Vercel AI SDK LanguageModel.
|
|
7
|
+
*
|
|
8
|
+
* This eliminates the need for consumers to write their own adapter
|
|
9
|
+
* when using @ai-sdk/openai, @ai-sdk/anthropic, @ai-sdk/google-vertex,
|
|
10
|
+
* or any other Vercel AI SDK-compatible provider.
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* import { createLLMClientFromModel } from "libretto/llm";
|
|
15
|
+
* import { openai } from "@ai-sdk/openai";
|
|
16
|
+
*
|
|
17
|
+
* const llmClient = createLLMClientFromModel(openai("gpt-4o"));
|
|
18
|
+
* ```
|
|
19
|
+
*/
|
|
20
|
+
declare function createLLMClientFromModel(model: LanguageModel): LLMClient;
|
|
21
|
+
|
|
22
|
+
export { createLLMClientFromModel };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { generateObject } from "ai";
|
|
2
|
+
function createLLMClientFromModel(model) {
|
|
3
|
+
return {
|
|
4
|
+
async generateObject(opts) {
|
|
5
|
+
const { object } = await generateObject({
|
|
6
|
+
model,
|
|
7
|
+
schema: opts.schema,
|
|
8
|
+
prompt: opts.prompt,
|
|
9
|
+
temperature: opts.temperature ?? 0
|
|
10
|
+
});
|
|
11
|
+
return object;
|
|
12
|
+
},
|
|
13
|
+
async generateObjectFromMessages(opts) {
|
|
14
|
+
const messages = opts.messages.map((msg) => {
|
|
15
|
+
if (typeof msg.content === "string") {
|
|
16
|
+
return { role: msg.role, content: msg.content };
|
|
17
|
+
}
|
|
18
|
+
if (msg.role === "assistant") {
|
|
19
|
+
return {
|
|
20
|
+
role: "assistant",
|
|
21
|
+
content: msg.content.filter((part) => part.type === "text").map((part) => ({ type: "text", text: part.text }))
|
|
22
|
+
};
|
|
23
|
+
}
|
|
24
|
+
return {
|
|
25
|
+
role: "user",
|
|
26
|
+
content: msg.content.map(
|
|
27
|
+
(part) => part.type === "text" ? { type: "text", text: part.text } : { type: "image", image: part.image }
|
|
28
|
+
)
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
const { object } = await generateObject({
|
|
32
|
+
model,
|
|
33
|
+
schema: opts.schema,
|
|
34
|
+
messages,
|
|
35
|
+
temperature: opts.temperature ?? 0
|
|
36
|
+
});
|
|
37
|
+
return object;
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
}
|
|
41
|
+
export {
|
|
42
|
+
createLLMClientFromModel
|
|
43
|
+
};
|
|
@@ -18,11 +18,14 @@ var __copyProps = (to, from, except, desc) => {
|
|
|
18
18
|
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
19
|
var llm_exports = {};
|
|
20
20
|
__export(llm_exports, {
|
|
21
|
-
createLLMClient: () => import_client.createLLMClient
|
|
21
|
+
createLLMClient: () => import_client.createLLMClient,
|
|
22
|
+
createLLMClientFromModel: () => import_ai_sdk_adapter.createLLMClientFromModel
|
|
22
23
|
});
|
|
23
24
|
module.exports = __toCommonJS(llm_exports);
|
|
24
25
|
var import_client = require("./client.js");
|
|
26
|
+
var import_ai_sdk_adapter = require("./ai-sdk-adapter.js");
|
|
25
27
|
// Annotate the CommonJS export names for ESM import in node:
|
|
26
28
|
0 && (module.exports = {
|
|
27
|
-
createLLMClient
|
|
29
|
+
createLLMClient,
|
|
30
|
+
createLLMClientFromModel
|
|
28
31
|
});
|
package/dist/shared/llm/index.js
CHANGED
|
@@ -17,13 +17,45 @@ type Message = {
|
|
|
17
17
|
* Users provide their own implementation backed by any LLM provider
|
|
18
18
|
* (OpenAI, Anthropic, etc.). Libretto uses this interface for AI extraction,
|
|
19
19
|
* recovery agents, and error detection.
|
|
20
|
+
*
|
|
21
|
+
* **Error handling:** implementations should throw on failure rather than
|
|
22
|
+
* returning sentinel values (e.g. `null` or `undefined`). Libretto relies
|
|
23
|
+
* on exceptions to trigger retry/recovery logic.
|
|
24
|
+
*
|
|
25
|
+
* A ready-made adapter for the Vercel AI SDK is available via
|
|
26
|
+
* {@link createLLMClientFromModel} in `libretto/llm`.
|
|
20
27
|
*/
|
|
21
28
|
interface LLMClient {
|
|
29
|
+
/**
|
|
30
|
+
* Generate a structured object from a single text prompt.
|
|
31
|
+
*
|
|
32
|
+
* The underlying model **must** support structured / JSON output so that
|
|
33
|
+
* the response can be parsed and validated against the provided Zod schema.
|
|
34
|
+
*
|
|
35
|
+
* @param opts.prompt - The text prompt sent to the model.
|
|
36
|
+
* @param opts.schema - A Zod schema describing the expected response shape.
|
|
37
|
+
* @param opts.temperature - Sampling temperature (default chosen by implementation, typically 0).
|
|
38
|
+
* @returns The parsed object matching the schema.
|
|
39
|
+
* @throws On LLM or parsing failure.
|
|
40
|
+
*/
|
|
22
41
|
generateObject<T extends z.ZodType>(opts: {
|
|
23
42
|
prompt: string;
|
|
24
43
|
schema: T;
|
|
25
44
|
temperature?: number;
|
|
26
45
|
}): Promise<z.infer<T>>;
|
|
46
|
+
/**
|
|
47
|
+
* Generate a structured object from a conversation-style message array.
|
|
48
|
+
*
|
|
49
|
+
* Messages may contain **image content** (base64 data URIs via
|
|
50
|
+
* {@link MessageContentPart}), so the backing model must support
|
|
51
|
+
* vision / multimodal input when images are present.
|
|
52
|
+
*
|
|
53
|
+
* @param opts.messages - Ordered list of user/assistant messages, potentially multimodal.
|
|
54
|
+
* @param opts.schema - A Zod schema describing the expected response shape.
|
|
55
|
+
* @param opts.temperature - Sampling temperature (default chosen by implementation, typically 0).
|
|
56
|
+
* @returns The parsed object matching the schema.
|
|
57
|
+
* @throws On LLM or parsing failure.
|
|
58
|
+
*/
|
|
27
59
|
generateObjectFromMessages<T extends z.ZodType>(opts: {
|
|
28
60
|
messages: Message[];
|
|
29
61
|
schema: T;
|
|
@@ -17,13 +17,45 @@ type Message = {
|
|
|
17
17
|
* Users provide their own implementation backed by any LLM provider
|
|
18
18
|
* (OpenAI, Anthropic, etc.). Libretto uses this interface for AI extraction,
|
|
19
19
|
* recovery agents, and error detection.
|
|
20
|
+
*
|
|
21
|
+
* **Error handling:** implementations should throw on failure rather than
|
|
22
|
+
* returning sentinel values (e.g. `null` or `undefined`). Libretto relies
|
|
23
|
+
* on exceptions to trigger retry/recovery logic.
|
|
24
|
+
*
|
|
25
|
+
* A ready-made adapter for the Vercel AI SDK is available via
|
|
26
|
+
* {@link createLLMClientFromModel} in `libretto/llm`.
|
|
20
27
|
*/
|
|
21
28
|
interface LLMClient {
|
|
29
|
+
/**
|
|
30
|
+
* Generate a structured object from a single text prompt.
|
|
31
|
+
*
|
|
32
|
+
* The underlying model **must** support structured / JSON output so that
|
|
33
|
+
* the response can be parsed and validated against the provided Zod schema.
|
|
34
|
+
*
|
|
35
|
+
* @param opts.prompt - The text prompt sent to the model.
|
|
36
|
+
* @param opts.schema - A Zod schema describing the expected response shape.
|
|
37
|
+
* @param opts.temperature - Sampling temperature (default chosen by implementation, typically 0).
|
|
38
|
+
* @returns The parsed object matching the schema.
|
|
39
|
+
* @throws On LLM or parsing failure.
|
|
40
|
+
*/
|
|
22
41
|
generateObject<T extends z.ZodType>(opts: {
|
|
23
42
|
prompt: string;
|
|
24
43
|
schema: T;
|
|
25
44
|
temperature?: number;
|
|
26
45
|
}): Promise<z.infer<T>>;
|
|
46
|
+
/**
|
|
47
|
+
* Generate a structured object from a conversation-style message array.
|
|
48
|
+
*
|
|
49
|
+
* Messages may contain **image content** (base64 data URIs via
|
|
50
|
+
* {@link MessageContentPart}), so the backing model must support
|
|
51
|
+
* vision / multimodal input when images are present.
|
|
52
|
+
*
|
|
53
|
+
* @param opts.messages - Ordered list of user/assistant messages, potentially multimodal.
|
|
54
|
+
* @param opts.schema - A Zod schema describing the expected response shape.
|
|
55
|
+
* @param opts.temperature - Sampling temperature (default chosen by implementation, typically 0).
|
|
56
|
+
* @returns The parsed object matching the schema.
|
|
57
|
+
* @throws On LLM or parsing failure.
|
|
58
|
+
*/
|
|
27
59
|
generateObjectFromMessages<T extends z.ZodType>(opts: {
|
|
28
60
|
messages: Message[];
|
|
29
61
|
schema: T;
|