@plico-ai/runtime 0.0.0-stage → 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 (188) hide show
  1. package/LICENSE +202 -0
  2. package/NOTICE +4 -0
  3. package/README.md +11 -2
  4. package/dist/artifacts.d.ts +10 -0
  5. package/dist/artifacts.js +106 -0
  6. package/dist/engine/context.d.ts +16 -0
  7. package/dist/engine/context.js +77 -0
  8. package/dist/engine/engine.d.ts +12 -0
  9. package/dist/engine/engine.js +235 -0
  10. package/dist/engine/errors.d.ts +12 -0
  11. package/dist/engine/errors.js +19 -0
  12. package/dist/engine/index.d.ts +7 -0
  13. package/dist/engine/index.js +5 -0
  14. package/dist/engine/journal.d.ts +65 -0
  15. package/dist/engine/journal.js +1 -0
  16. package/dist/engine/memory-journal.d.ts +2 -0
  17. package/dist/engine/memory-journal.js +125 -0
  18. package/dist/engine/sqlite-engine.d.ts +7 -0
  19. package/dist/engine/sqlite-engine.js +6 -0
  20. package/dist/engine/sqlite-journal.d.ts +5 -0
  21. package/dist/engine/sqlite-journal.js +136 -0
  22. package/dist/engine/types.d.ts +97 -0
  23. package/dist/engine/types.js +1 -0
  24. package/dist/env.d.ts +7 -0
  25. package/dist/env.js +19 -0
  26. package/dist/errors.d.ts +18 -0
  27. package/dist/errors.js +40 -0
  28. package/dist/evals/discover.d.ts +3 -0
  29. package/dist/evals/discover.js +49 -0
  30. package/dist/evals/index.d.ts +3 -0
  31. package/dist/evals/index.js +3 -0
  32. package/dist/evals/promote.d.ts +7 -0
  33. package/dist/evals/promote.js +32 -0
  34. package/dist/evals/run-evals.d.ts +2 -0
  35. package/dist/evals/run-evals.js +69 -0
  36. package/dist/events.d.ts +28 -0
  37. package/dist/events.js +104 -0
  38. package/dist/guards.d.ts +1 -0
  39. package/dist/guards.js +3 -0
  40. package/dist/index.d.ts +18 -0
  41. package/dist/index.js +17 -0
  42. package/dist/instructions.d.ts +4 -0
  43. package/dist/instructions.js +23 -0
  44. package/dist/policy/approval.d.ts +8 -0
  45. package/dist/policy/approval.js +27 -0
  46. package/dist/providers/ai-sdk.d.ts +10 -0
  47. package/dist/providers/ai-sdk.js +154 -0
  48. package/dist/providers/configured.d.ts +17 -0
  49. package/dist/providers/configured.js +60 -0
  50. package/dist/providers/openai-compatible.d.ts +8 -0
  51. package/dist/providers/openai-compatible.js +14 -0
  52. package/dist/providers/project-module.d.ts +7 -0
  53. package/dist/providers/project-module.js +29 -0
  54. package/dist/providers/registry.d.ts +20 -0
  55. package/dist/providers/registry.js +53 -0
  56. package/dist/readiness/check-readiness.d.ts +2 -0
  57. package/dist/readiness/check-readiness.js +33 -0
  58. package/dist/readiness/checks/approval-policy.d.ts +5 -0
  59. package/dist/readiness/checks/approval-policy.js +19 -0
  60. package/dist/readiness/checks/artifact-access.d.ts +3 -0
  61. package/dist/readiness/checks/artifact-access.js +5 -0
  62. package/dist/readiness/checks/artifacts.d.ts +6 -0
  63. package/dist/readiness/checks/artifacts.js +22 -0
  64. package/dist/readiness/checks/env.d.ts +3 -0
  65. package/dist/readiness/checks/env.js +10 -0
  66. package/dist/readiness/checks/evals.d.ts +2 -0
  67. package/dist/readiness/checks/evals.js +53 -0
  68. package/dist/readiness/checks/persistence.d.ts +3 -0
  69. package/dist/readiness/checks/persistence.js +61 -0
  70. package/dist/readiness/checks/project.d.ts +7 -0
  71. package/dist/readiness/checks/project.js +21 -0
  72. package/dist/readiness/checks/provider.d.ts +2 -0
  73. package/dist/readiness/checks/provider.js +20 -0
  74. package/dist/readiness/checks/server-config.d.ts +2 -0
  75. package/dist/readiness/checks/server-config.js +13 -0
  76. package/dist/readiness/checks/studio.d.ts +2 -0
  77. package/dist/readiness/checks/studio.js +16 -0
  78. package/dist/readiness/checks/thread-store.d.ts +3 -0
  79. package/dist/readiness/checks/thread-store.js +12 -0
  80. package/dist/readiness/checks/tools.d.ts +3 -0
  81. package/dist/readiness/checks/tools.js +42 -0
  82. package/dist/readiness/diagnostic.d.ts +2 -0
  83. package/dist/readiness/diagnostic.js +7 -0
  84. package/dist/readiness/index.d.ts +1 -0
  85. package/dist/readiness/index.js +1 -0
  86. package/dist/readiness/open-database.d.ts +8 -0
  87. package/dist/readiness/open-database.js +15 -0
  88. package/dist/run/artifact-tool-context.d.ts +19 -0
  89. package/dist/run/artifact-tool-context.js +74 -0
  90. package/dist/run/finalize.d.ts +16 -0
  91. package/dist/run/finalize.js +11 -0
  92. package/dist/run/index.d.ts +1 -0
  93. package/dist/run/index.js +1 -0
  94. package/dist/run/pinned-instructions.d.ts +18 -0
  95. package/dist/run/pinned-instructions.js +36 -0
  96. package/dist/run/record-tools.d.ts +8 -0
  97. package/dist/run/record-tools.js +21 -0
  98. package/dist/run/run-project.d.ts +17 -0
  99. package/dist/run/run-project.js +222 -0
  100. package/dist/run/strategies/approval.d.ts +9 -0
  101. package/dist/run/strategies/approval.js +42 -0
  102. package/dist/run/strategies/default-dry.d.ts +3 -0
  103. package/dist/run/strategies/default-dry.js +5 -0
  104. package/dist/run/strategies/provider.d.ts +6 -0
  105. package/dist/run/strategies/provider.js +193 -0
  106. package/dist/run/strategies/scripted.d.ts +5 -0
  107. package/dist/run/strategies/scripted.js +106 -0
  108. package/dist/run/tool-fingerprint.d.ts +2 -0
  109. package/dist/run/tool-fingerprint.js +26 -0
  110. package/dist/run/tool-step.d.ts +4 -0
  111. package/dist/run/tool-step.js +62 -0
  112. package/dist/run/tracing.d.ts +12 -0
  113. package/dist/run/tracing.js +92 -0
  114. package/dist/script.d.ts +4 -0
  115. package/dist/script.js +51 -0
  116. package/dist/storage/index.d.ts +1 -0
  117. package/dist/storage/index.js +1 -0
  118. package/dist/storage/metadata.d.ts +5 -0
  119. package/dist/storage/metadata.js +26 -0
  120. package/dist/storage/sqlite/append-event.d.ts +3 -0
  121. package/dist/storage/sqlite/append-event.js +108 -0
  122. package/dist/storage/sqlite/driver.d.ts +9 -0
  123. package/dist/storage/sqlite/driver.js +13 -0
  124. package/dist/storage/sqlite/index.d.ts +1 -0
  125. package/dist/storage/sqlite/index.js +1 -0
  126. package/dist/storage/sqlite/open.d.ts +3 -0
  127. package/dist/storage/sqlite/open.js +54 -0
  128. package/dist/storage/sqlite/owner-lock.d.ts +5 -0
  129. package/dist/storage/sqlite/owner-lock.js +55 -0
  130. package/dist/storage/sqlite/project-thread.d.ts +4 -0
  131. package/dist/storage/sqlite/project-thread.js +33 -0
  132. package/dist/storage/sqlite/queries.d.ts +9 -0
  133. package/dist/storage/sqlite/queries.js +134 -0
  134. package/dist/storage/sqlite/recover-interrupted.d.ts +2 -0
  135. package/dist/storage/sqlite/recover-interrupted.js +46 -0
  136. package/dist/storage/sqlite/schema.d.ts +10 -0
  137. package/dist/storage/sqlite/schema.js +205 -0
  138. package/dist/storage/sqlite/store.d.ts +2 -0
  139. package/dist/storage/sqlite/store.js +51 -0
  140. package/dist/storage/sqlite/thread-log.d.ts +4 -0
  141. package/dist/storage/sqlite/thread-log.js +9 -0
  142. package/dist/storage/sqlite/thread-title.d.ts +24 -0
  143. package/dist/storage/sqlite/thread-title.js +85 -0
  144. package/dist/storage/sqlite/threads.d.ts +47 -0
  145. package/dist/storage/sqlite/threads.js +156 -0
  146. package/dist/threads/stopwords.d.ts +1 -0
  147. package/dist/threads/stopwords.js +16 -0
  148. package/dist/threads/suggest-title.d.ts +9 -0
  149. package/dist/threads/suggest-title.js +102 -0
  150. package/dist/threads/titler.d.ts +10 -0
  151. package/dist/threads/titler.js +63 -0
  152. package/dist/threads/words.d.ts +12 -0
  153. package/dist/threads/words.js +39 -0
  154. package/dist/tools/artifact-model-tool-operations.d.ts +29 -0
  155. package/dist/tools/artifact-model-tool-operations.js +124 -0
  156. package/dist/tools/artifact-model-tools.d.ts +2 -0
  157. package/dist/tools/artifact-model-tools.js +101 -0
  158. package/dist/tools/discover.d.ts +4 -0
  159. package/dist/tools/discover.js +34 -0
  160. package/dist/tools/index.d.ts +3 -0
  161. package/dist/tools/index.js +3 -0
  162. package/dist/tools/load.d.ts +2 -0
  163. package/dist/tools/load.js +83 -0
  164. package/dist/tools/normalize.d.ts +2 -0
  165. package/dist/tools/normalize.js +48 -0
  166. package/dist/tools/schema.d.ts +7 -0
  167. package/dist/tools/schema.js +101 -0
  168. package/dist/tools/skill-model-tool.d.ts +7 -0
  169. package/dist/tools/skill-model-tool.js +38 -0
  170. package/dist/types/artifacts.d.ts +5 -0
  171. package/dist/types/artifacts.js +1 -0
  172. package/dist/types/evals.d.ts +16 -0
  173. package/dist/types/evals.js +1 -0
  174. package/dist/types/index.d.ts +10 -0
  175. package/dist/types/index.js +1 -0
  176. package/dist/types/provider.d.ts +45 -0
  177. package/dist/types/provider.js +1 -0
  178. package/dist/types/readiness.d.ts +9 -0
  179. package/dist/types/readiness.js +1 -0
  180. package/dist/types/run.d.ts +28 -0
  181. package/dist/types/run.js +1 -0
  182. package/dist/types/script.d.ts +16 -0
  183. package/dist/types/script.js +1 -0
  184. package/dist/types/store.d.ts +24 -0
  185. package/dist/types/store.js +1 -0
  186. package/dist/types/tools.d.ts +15 -0
  187. package/dist/types/tools.js +1 -0
  188. package/package.json +77 -3
@@ -0,0 +1,101 @@
1
+ import { ARTIFACT_TOOL_NAMES } from "@plico-ai/core";
2
+ import { editFile, listFiles, readFile, writeFile } from "./artifact-model-tool-operations.js";
3
+ import { normalizeInputSchema } from "./schema.js";
4
+ const source = "plico:artifacts";
5
+ const maxListLimit = 1000;
6
+ const maxReadLimit = 1000;
7
+ export async function createArtifactModelTools() {
8
+ return Promise.all([
9
+ createDeclaredTool({
10
+ name: "list_files",
11
+ description: "List artifact files in the current workspace. Optionally filter paths with a glob pattern. Results are ordered by path and paginated.",
12
+ inputSchema: {
13
+ type: "object",
14
+ properties: {
15
+ glob: { type: "string", minLength: 1, maxLength: 1024 },
16
+ offset: { type: "integer", minimum: 0 },
17
+ limit: { type: "integer", minimum: 1, maximum: maxListLimit },
18
+ },
19
+ additionalProperties: false,
20
+ },
21
+ capabilities: ["artifacts:read"],
22
+ approval: { required: false },
23
+ handler: async (input, { artifacts }) => handleArtifactTool(() => listFiles(input, artifacts)),
24
+ }),
25
+ createDeclaredTool({
26
+ name: "read_file",
27
+ description: "Read a text artifact from the current workspace by line range. Binary artifacts return metadata only. Each response is capped at 32 KiB.",
28
+ inputSchema: {
29
+ type: "object",
30
+ properties: {
31
+ path: { type: "string", minLength: 1, maxLength: 1024 },
32
+ offset: { type: "integer", minimum: 1 },
33
+ limit: { type: "integer", minimum: 1, maximum: maxReadLimit },
34
+ },
35
+ required: ["path"],
36
+ additionalProperties: false,
37
+ },
38
+ capabilities: ["artifacts:read"],
39
+ approval: { required: false },
40
+ handler: async (input, { artifacts }) => handleArtifactTool(() => readFile(input, artifacts)),
41
+ }),
42
+ createDeclaredTool({
43
+ name: "write_file",
44
+ description: "Create or overwrite a text artifact in the current workspace. Writes are versioned. Content is limited to 1 MiB.",
45
+ inputSchema: {
46
+ type: "object",
47
+ properties: {
48
+ path: { type: "string", minLength: 1, maxLength: 1024 },
49
+ content: { type: "string" },
50
+ mimeType: { type: "string", minLength: 1 },
51
+ },
52
+ required: ["path", "content"],
53
+ additionalProperties: false,
54
+ },
55
+ capabilities: ["artifacts:write"],
56
+ approval: { required: false },
57
+ handler: async (input, { artifacts }) => handleArtifactTool(() => writeFile(input, artifacts)),
58
+ }),
59
+ createDeclaredTool({
60
+ name: "edit_file",
61
+ description: "Replace exact text in a text artifact. The old text must match once unless replaceAll is true. Writes are versioned.",
62
+ inputSchema: {
63
+ type: "object",
64
+ properties: {
65
+ path: { type: "string", minLength: 1, maxLength: 1024 },
66
+ old: { type: "string", minLength: 1 },
67
+ new: { type: "string" },
68
+ replaceAll: { type: "boolean" },
69
+ },
70
+ required: ["path", "old", "new"],
71
+ additionalProperties: false,
72
+ },
73
+ capabilities: ["artifacts:write"],
74
+ approval: { required: false },
75
+ handler: async (input, { artifacts }) => handleArtifactTool(() => editFile(input, artifacts)),
76
+ }),
77
+ ]);
78
+ }
79
+ async function handleArtifactTool(operation) {
80
+ try {
81
+ return await operation();
82
+ }
83
+ catch (error) {
84
+ return { error: error instanceof Error ? error.message : String(error) };
85
+ }
86
+ }
87
+ async function createDeclaredTool(definition) {
88
+ if (!ARTIFACT_TOOL_NAMES.includes(definition.name))
89
+ throw new Error(`Unknown built-in artifact tool: ${definition.name}`);
90
+ const schema = await normalizeInputSchema(definition.inputSchema, source, source);
91
+ return {
92
+ ...definition,
93
+ source,
94
+ inputSchema: schema.jsonSchema,
95
+ validateInput: async (input) => {
96
+ const result = await schema.parse(input);
97
+ return result.success ? undefined : result.error;
98
+ },
99
+ parseInput: schema.parse,
100
+ };
101
+ }
@@ -0,0 +1,4 @@
1
+ import { type LoadedProject } from "@plico-ai/core";
2
+ import type { DeclaredTool } from "../types/index.js";
3
+ export declare function discoverToolFiles(project: LoadedProject): Promise<string[]>;
4
+ export declare function discoverTools(project: LoadedProject): Promise<DeclaredTool[]>;
@@ -0,0 +1,34 @@
1
+ import { readdir } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { ARTIFACT_TOOL_NAMES, getProjectPaths, getProjectRelativePaths, SKILL_TOOL_NAME, } from "@plico-ai/core";
4
+ import { loadToolFile } from "./load.js";
5
+ export async function discoverToolFiles(project) {
6
+ const projectPaths = getProjectPaths(project.root);
7
+ const entries = (await readdir(projectPaths.directories.tools, { withFileTypes: true }))
8
+ .filter((entry) => !entry.isDirectory() && entry.name.endsWith(".tool.ts"))
9
+ .map((entry) => entry.name)
10
+ .sort((left, right) => left.localeCompare(right));
11
+ return entries;
12
+ }
13
+ export async function discoverTools(project) {
14
+ const relativePaths = getProjectRelativePaths();
15
+ const projectPaths = getProjectPaths(project.root);
16
+ const entries = await discoverToolFiles(project);
17
+ const tools = [];
18
+ const sources = new Map();
19
+ for (const entry of entries) {
20
+ const source = `${relativePaths.directories.tools}/${entry}`;
21
+ const tool = await loadToolFile(join(projectPaths.directories.tools, entry), source);
22
+ if (ARTIFACT_TOOL_NAMES.includes(tool.name))
23
+ throw new Error(`Tool name "${tool.name}" is reserved by Plico's artifact tools`);
24
+ if (tool.name === SKILL_TOOL_NAME)
25
+ throw new Error(`Tool name "${tool.name}" is reserved by Plico's skill loader`);
26
+ const first = sources.get(tool.name);
27
+ if (first) {
28
+ throw new Error(`Duplicate tool name "${tool.name}" declared in ${first} and ${source}`);
29
+ }
30
+ sources.set(tool.name, source);
31
+ tools.push(tool);
32
+ }
33
+ return tools;
34
+ }
@@ -0,0 +1,3 @@
1
+ export { discoverToolFiles, discoverTools } from "./discover.js";
2
+ export { loadToolFile } from "./load.js";
3
+ export { isJsonSchema, normalizeInputSchema, } from "./schema.js";
@@ -0,0 +1,3 @@
1
+ export { discoverToolFiles, discoverTools } from "./discover.js";
2
+ export { loadToolFile } from "./load.js";
3
+ export { isJsonSchema, normalizeInputSchema, } from "./schema.js";
@@ -0,0 +1,2 @@
1
+ import type { DeclaredTool } from "../types/index.js";
2
+ export declare function loadToolFile(toolPath: string, source: string): Promise<DeclaredTool>;
@@ -0,0 +1,83 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { createRequire } from "node:module";
3
+ import { dirname, extname, isAbsolute, join, parse, relative } from "node:path";
4
+ import { pathToFileURL } from "node:url";
5
+ import { installAuthoringFallback } from "@plico-ai/core";
6
+ import { register as registerCjs, require as tsxRequire } from "tsx/cjs/api";
7
+ import { register as registerEsm } from "tsx/esm/api";
8
+ import { isRecord } from "../guards.js";
9
+ import { normalizeDeclaredTool } from "./normalize.js";
10
+ let cjsRegistered = false;
11
+ let esmRegistered = false;
12
+ let loadSequence = 0;
13
+ export async function loadToolFile(toolPath, source) {
14
+ installAuthoringFallback();
15
+ const module = (await hasModulePackageScope(toolPath))
16
+ ? await importToolModule(toolPath)
17
+ : importCommonJsTool(toolPath);
18
+ const exportedTool = readDefaultExport(module, source);
19
+ return normalizeDeclaredTool(exportedTool, source, toolPath);
20
+ }
21
+ async function importToolModule(toolPath) {
22
+ if (!esmRegistered) {
23
+ registerEsm();
24
+ esmRegistered = true;
25
+ }
26
+ const url = new URL(pathToFileURL(toolPath).href);
27
+ url.searchParams.set("plicoLoad", String(++loadSequence));
28
+ return import(url.href);
29
+ }
30
+ function importCommonJsTool(toolPath) {
31
+ if (!cjsRegistered) {
32
+ registerCjs();
33
+ cjsRegistered = true;
34
+ }
35
+ const require = createRequire(import.meta.url);
36
+ clearProjectToolCache(toolPath);
37
+ return tsxRequire(require.resolve(toolPath), import.meta.url);
38
+ }
39
+ function clearProjectToolCache(toolPath) {
40
+ const toolsDirectory = findToolsDirectory(dirname(toolPath));
41
+ for (const cachedPath of Object.keys(tsxRequire.cache)) {
42
+ const sourcePath = cachedPath.split("?", 1)[0];
43
+ if (!sourcePath)
44
+ continue;
45
+ if (extname(sourcePath) !== ".ts")
46
+ continue;
47
+ const pathFromTools = relative(toolsDirectory, sourcePath);
48
+ if (pathFromTools === "" || (!pathFromTools.startsWith("..") && !isAbsolute(pathFromTools))) {
49
+ delete tsxRequire.cache[cachedPath];
50
+ }
51
+ }
52
+ }
53
+ function findToolsDirectory(directory) {
54
+ if (directory === parse(directory).root)
55
+ return directory;
56
+ if (directory.split(/[\\/]/).at(-1) === "tools")
57
+ return directory;
58
+ return findToolsDirectory(dirname(directory));
59
+ }
60
+ async function hasModulePackageScope(filePath) {
61
+ let directory = dirname(filePath);
62
+ const filesystemRoot = parse(directory).root;
63
+ while (true) {
64
+ try {
65
+ const packageJson = JSON.parse(await readFile(join(directory, "package.json"), "utf8"));
66
+ return packageJson.type === "module";
67
+ }
68
+ catch (error) {
69
+ if (!error || typeof error !== "object" || !("code" in error) || error.code !== "ENOENT") {
70
+ throw error;
71
+ }
72
+ }
73
+ if (directory === filesystemRoot)
74
+ return false;
75
+ directory = dirname(directory);
76
+ }
77
+ }
78
+ function readDefaultExport(toolModule, source) {
79
+ if (!isRecord(toolModule) || !Object.hasOwn(toolModule, "default")) {
80
+ throw new Error(`${source} must default export a declared tool`);
81
+ }
82
+ return toolModule.default;
83
+ }
@@ -0,0 +1,2 @@
1
+ import type { DeclaredTool } from "../types/index.js";
2
+ export declare function normalizeDeclaredTool(value: unknown, source: string, toolPath: string): Promise<DeclaredTool>;
@@ -0,0 +1,48 @@
1
+ import { isRecord } from "../guards.js";
2
+ import { normalizeInputSchema } from "./schema.js";
3
+ export async function normalizeDeclaredTool(value, source, toolPath) {
4
+ if (!isRecord(value)) {
5
+ throw new Error(`${source} must default export a declared tool object`);
6
+ }
7
+ const { name, description, inputSchema, capabilities, approval, handler } = value;
8
+ if (typeof name !== "string") {
9
+ throw new Error(`${source} tool name must be a string`);
10
+ }
11
+ if (!/^[a-z][a-z0-9_]*$/.test(name)) {
12
+ throw new Error(`${source} tool name must match /^[a-z][a-z0-9_]*$/`);
13
+ }
14
+ if (typeof description !== "string") {
15
+ throw new Error(`${source} tool description must be a string`);
16
+ }
17
+ const normalizedInputSchema = await normalizeInputSchema(inputSchema, source, toolPath);
18
+ if (!Array.isArray(capabilities) ||
19
+ !capabilities.every((capability) => typeof capability === "string")) {
20
+ throw new Error(`${source} capabilities must be an array of strings`);
21
+ }
22
+ if (!isRecord(approval) || typeof approval.required !== "boolean") {
23
+ throw new Error(`${source} approval must declare a required boolean`);
24
+ }
25
+ if (!isToolHandler(handler)) {
26
+ throw new Error(`${source} handler must be a function`);
27
+ }
28
+ return {
29
+ source,
30
+ name,
31
+ description,
32
+ inputSchema: normalizedInputSchema.jsonSchema,
33
+ async validateInput(input) {
34
+ const result = await normalizedInputSchema.parse(input);
35
+ return result.success ? undefined : result.error;
36
+ },
37
+ parseInput: normalizedInputSchema.parse,
38
+ capabilities,
39
+ approval: {
40
+ required: approval.required,
41
+ ...(typeof approval.reason === "string" ? { reason: approval.reason } : {}),
42
+ },
43
+ handler,
44
+ };
45
+ }
46
+ function isToolHandler(value) {
47
+ return typeof value === "function";
48
+ }
@@ -0,0 +1,7 @@
1
+ import type { JsonSchema, ToolInputParseResult } from "../types/index.js";
2
+ export interface NormalizedInputSchema {
3
+ jsonSchema: JsonSchema;
4
+ parse(value: unknown): Promise<ToolInputParseResult>;
5
+ }
6
+ export declare function normalizeInputSchema(value: unknown, source: string, toolPath: string): Promise<NormalizedInputSchema>;
7
+ export declare function isJsonSchema(value: unknown): value is JsonSchema;
@@ -0,0 +1,101 @@
1
+ import { createRequire } from "node:module";
2
+ import { pathToFileURL } from "node:url";
3
+ import { Ajv } from "ajv";
4
+ import { zodToJsonSchema } from "zod-to-json-schema";
5
+ const ajv = new Ajv({ allErrors: true, strict: false });
6
+ const addFormats = createRequire(import.meta.url)("ajv-formats");
7
+ addFormats(ajv);
8
+ export async function normalizeInputSchema(value, source, toolPath) {
9
+ if (isZodSchema(value)) {
10
+ return {
11
+ jsonSchema: await convertZodSchema(value, source, toolPath),
12
+ async parse(input) {
13
+ const result = await value.safeParseAsync(input);
14
+ if (result.success)
15
+ return { success: true, value: result.data };
16
+ return {
17
+ success: false,
18
+ error: result.error.issues
19
+ .map((issue) => `${issue.path.join(".") || "input"}: ${issue.message}`)
20
+ .join("; "),
21
+ };
22
+ },
23
+ };
24
+ }
25
+ if (!isJsonSchema(value)) {
26
+ throw new Error(`${source} inputSchema must be a Zod schema or JSON Schema`);
27
+ }
28
+ let validator;
29
+ try {
30
+ validator = ajv.compile(value);
31
+ }
32
+ catch (error) {
33
+ const message = error instanceof Error ? error.message : String(error);
34
+ throw new Error(`${source} inputSchema is not a valid JSON Schema: ${message}`);
35
+ }
36
+ return {
37
+ jsonSchema: value,
38
+ async parse(input) {
39
+ const error = validateJsonSchemaWithAjv(input, validator);
40
+ return error ? { success: false, error } : { success: true, value: input };
41
+ },
42
+ };
43
+ }
44
+ export function isJsonSchema(value) {
45
+ return typeof value === "boolean" || isJsonObject(value);
46
+ }
47
+ function validateJsonSchemaWithAjv(value, validator) {
48
+ if (validator(value))
49
+ return undefined;
50
+ const issues = validator.errors?.map(formatAjvIssue) ?? [];
51
+ return issues.length === 0 ? "input does not match the schema" : issues.join("; ");
52
+ }
53
+ function formatAjvIssue(issue) {
54
+ const path = jsonPointerPath(issue.instancePath);
55
+ if (issue.keyword === "required") {
56
+ const property = issue.params.missingProperty;
57
+ return `${location(path ? `${path}.${property}` : property)}missing required property ${property}`;
58
+ }
59
+ if (issue.keyword === "additionalProperties") {
60
+ const property = issue.params.additionalProperty;
61
+ return `${location(path ? `${path}.${property}` : property)}unknown property ${property}`;
62
+ }
63
+ if (issue.keyword === "type") {
64
+ return `${location(path)}expected ${issue.params.type}`;
65
+ }
66
+ return `${location(path)}${issue.message ?? "invalid"}`;
67
+ }
68
+ function location(path) {
69
+ return path ? `${path}: ` : "";
70
+ }
71
+ function jsonPointerPath(instancePath) {
72
+ return instancePath
73
+ .split("/")
74
+ .slice(1)
75
+ .map((segment) => segment.replaceAll("~1", "/").replaceAll("~0", "~"))
76
+ .join(".");
77
+ }
78
+ async function convertZodSchema(schema, source, toolPath) {
79
+ if (!isJsonObject(schema) || !("_zod" in schema)) {
80
+ return zodToJsonSchema(schema);
81
+ }
82
+ try {
83
+ const requireFromTool = createRequire(toolPath);
84
+ const zodV4ModulePath = requireFromTool.resolve("zod/v4");
85
+ const zodV4 = (await import(pathToFileURL(zodV4ModulePath).href));
86
+ if (typeof zodV4.toJSONSchema !== "function") {
87
+ throw new Error("The installed Zod v4 package does not export toJSONSchema");
88
+ }
89
+ return zodV4.toJSONSchema(schema, { target: "draft-7" });
90
+ }
91
+ catch (error) {
92
+ const message = error instanceof Error ? error.message : String(error);
93
+ throw new Error(`${source} could not convert its Zod 4 schema to JSON Schema: ${message}`);
94
+ }
95
+ }
96
+ function isJsonObject(value) {
97
+ return value !== null && typeof value === "object" && !Array.isArray(value);
98
+ }
99
+ function isZodSchema(value) {
100
+ return isJsonObject(value) && typeof value.safeParseAsync === "function";
101
+ }
@@ -0,0 +1,7 @@
1
+ import { type Skill } from "@plico-ai/core";
2
+ import type { DeclaredTool } from "../types/index.js";
3
+ /**
4
+ * The tool that returns a skill's full text. It can only return a skill that `skills/` declared when
5
+ * the run started, so a name never reaches outside that folder.
6
+ */
7
+ export declare function createSkillModelTool(skills: Skill[]): Promise<DeclaredTool>;
@@ -0,0 +1,38 @@
1
+ import { SKILL_TOOL_NAME } from "@plico-ai/core";
2
+ import { normalizeInputSchema } from "./schema.js";
3
+ const source = "plico:skills";
4
+ /**
5
+ * The tool that returns a skill's full text. It can only return a skill that `skills/` declared when
6
+ * the run started, so a name never reaches outside that folder.
7
+ */
8
+ export async function createSkillModelTool(skills) {
9
+ const byName = new Map(skills.map((skill) => [skill.name, skill]));
10
+ const schema = await normalizeInputSchema({
11
+ type: "object",
12
+ properties: { name: { type: "string", minLength: 1, maxLength: 256 } },
13
+ required: ["name"],
14
+ additionalProperties: false,
15
+ }, source, source);
16
+ return {
17
+ name: SKILL_TOOL_NAME,
18
+ description: "Load the full instructions of one skill from the Skills list in your instructions, by name.",
19
+ capabilities: [],
20
+ approval: { required: false },
21
+ source,
22
+ inputSchema: schema.jsonSchema,
23
+ validateInput: async (input) => {
24
+ const result = await schema.parse(input);
25
+ return result.success ? undefined : result.error;
26
+ },
27
+ parseInput: schema.parse,
28
+ handler: async (input) => {
29
+ const name = input.name;
30
+ const skill = byName.get(name);
31
+ if (!skill)
32
+ return {
33
+ error: `Unknown skill: ${name}. Available skills: ${[...byName.keys()].join(", ")}.`,
34
+ };
35
+ return { name: skill.name, content: skill.body };
36
+ },
37
+ };
38
+ }
@@ -0,0 +1,5 @@
1
+ export interface ArtifactFileInput {
2
+ path: string;
3
+ content: string;
4
+ mimeType?: string;
5
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ import type { RunStatus } from "@plico-ai/contracts";
2
+ import type { DryRunScriptStep } from "./script.js";
3
+ import type { EventStore } from "./store.js";
4
+ export interface EvalExpectation {
5
+ status?: RunStatus;
6
+ outputContains?: string;
7
+ }
8
+ export interface EvalCase {
9
+ name: string;
10
+ description?: string;
11
+ script: DryRunScriptStep[];
12
+ expect?: EvalExpectation;
13
+ }
14
+ export interface RunEvalsOptions {
15
+ eventStore?: EventStore;
16
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,10 @@
1
+ import type { ArtifactContent, ArtifactFile, ArtifactFileMetadata, ArtifactSnapshot, ArtifactSnapshotDetail, ArtifactVersion, ArtifactWorkspace, ComposedInstructions, DiagnosticSeverity, EvalCaseResult, EvalReport, EvalSummary, PlicoEvent, PlicoEventType, ReadinessDiagnostic, ReadinessReport, RunResult, RunStatus, RunSummary } from "@plico-ai/contracts";
2
+ export type { ArtifactFileInput } from "./artifacts.js";
3
+ export type { EvalCase, EvalExpectation, RunEvalsOptions } from "./evals.js";
4
+ export type { ModelChunk, ModelProvider, ModelRequest, ModelResponse, ModelToolCall, ProviderMessage, } from "./provider.js";
5
+ export type { ReadinessOptions } from "./readiness.js";
6
+ export type { RunProjectOptions } from "./run.js";
7
+ export type { DryRunScriptStep } from "./script.js";
8
+ export type { CreateSqliteEventStoreOptions, EventStore } from "./store.js";
9
+ export type { DeclaredTool, JsonSchema, ToolApprovalPolicy, ToolArtifactContext, ToolArtifactFile, ToolDefinition, ToolHandlerContext, ToolInputParseResult, ToolInputSchema, ZodInputParseResult, ZodInputSchema, } from "./tools.js";
10
+ export type { ArtifactContent, ArtifactFile, ArtifactFileMetadata, ArtifactSnapshot, ArtifactSnapshotDetail, ArtifactVersion, ArtifactWorkspace, ComposedInstructions, DiagnosticSeverity, EvalCaseResult, EvalReport, EvalSummary, PlicoEvent, PlicoEventType, ReadinessDiagnostic, ReadinessReport, RunResult, RunStatus, RunSummary, };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,45 @@
1
+ import type { JsonValue, ModelToolCall } from "@plico-ai/contracts";
2
+ import type { JsonSchema } from "./tools.js";
3
+ export interface ProviderMessage {
4
+ role: "system" | "user" | "assistant" | "tool";
5
+ content: string;
6
+ toolCallId?: string;
7
+ toolName?: string;
8
+ toolCalls?: ModelToolCall[];
9
+ providerMetadata?: JsonValue;
10
+ }
11
+ export type { ModelToolCall } from "@plico-ai/contracts";
12
+ export interface ModelRequest {
13
+ messages: ProviderMessage[];
14
+ maxSteps: number;
15
+ tools?: Array<{
16
+ name: string;
17
+ description: string;
18
+ inputSchema: JsonSchema;
19
+ }>;
20
+ }
21
+ export interface ModelResponse {
22
+ providerMetadata?: JsonValue;
23
+ content: string;
24
+ usage: {
25
+ inputTokens: number;
26
+ outputTokens: number;
27
+ };
28
+ toolCalls?: ModelToolCall[];
29
+ }
30
+ export type ModelChunk = {
31
+ type: "text";
32
+ text: string;
33
+ } | {
34
+ type: "tool.call";
35
+ call: ModelToolCall;
36
+ } | {
37
+ type: "finish";
38
+ usage: ModelResponse["usage"];
39
+ providerMetadata?: JsonValue;
40
+ };
41
+ export interface ModelProvider {
42
+ stream(request: ModelRequest, options: {
43
+ signal: AbortSignal;
44
+ }): AsyncIterable<ModelChunk>;
45
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,9 @@
1
+ import type { ThreadStore } from "../storage/sqlite/threads.js";
2
+ import type { EventStore } from "./store.js";
3
+ export interface ReadinessOptions {
4
+ databasePath?: string;
5
+ eventStore?: EventStore;
6
+ threadStore?: Pick<ThreadStore, "storageIdentity">;
7
+ /** Built Studio directory. Omit when Studio is not in use. */
8
+ studioPath?: string | undefined;
9
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,28 @@
1
+ import type { JsonValue } from "@plico-ai/contracts";
2
+ import type { Engine } from "../engine/index.js";
3
+ import type { ModelProvider, ProviderMessage } from "./provider.js";
4
+ import type { DryRunScriptStep } from "./script.js";
5
+ import type { EventStore } from "./store.js";
6
+ export interface RunProjectOptions {
7
+ script?: DryRunScriptStep[];
8
+ /**
9
+ * Do not run tool handlers for scripted `tool.call` steps. Each step supplies its output as
10
+ * `result`; a step without one fails the run, and `live: true` opts a step back in to its handler.
11
+ */
12
+ mockTools?: boolean;
13
+ eventStore?: EventStore;
14
+ /** Runs the loop durably. Defaults to an in-memory engine that does not survive the process. */
15
+ engine?: Engine;
16
+ runId?: string;
17
+ provider?: ModelProvider;
18
+ /** Opaque identity used to prevent recovery with a different provider configuration. */
19
+ providerRecoveryKey?: string;
20
+ message?: string;
21
+ threadId?: string;
22
+ /** Host data stamped on `run.started`. Immutable and returned by run reads and filters. */
23
+ metadata?: Record<string, JsonValue>;
24
+ /** Host data passed to tools as `ctx.context` and recorded on `run.started`. No secrets. */
25
+ context?: Record<string, JsonValue>;
26
+ history?: Array<Pick<ProviderMessage, "role" | "content">>;
27
+ onStarted?: (runId: string) => void;
28
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ import type { ArtifactFileInput } from "./artifacts.js";
2
+ export type DryRunScriptStep = {
3
+ type: "assistant.output";
4
+ content: string;
5
+ } | {
6
+ type: "tool.call";
7
+ toolName: string;
8
+ arguments: unknown;
9
+ /** The output to use instead of running the tool, when the run mocks tools. */
10
+ result?: unknown;
11
+ /** Run the real handler even when the run mocks tools. */
12
+ live?: true;
13
+ } | {
14
+ type: "artifact.write";
15
+ files: ArtifactFileInput[];
16
+ };
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,24 @@
1
+ import type { EvalReport, JsonValue, PlicoEvent, RunSummary } from "@plico-ai/contracts";
2
+ export interface EventStore {
3
+ readonly storageIdentity?: string;
4
+ appendEvent(event: PlicoEvent): Promise<void>;
5
+ /** Lists runs, newest first. `metadata` keeps runs whose top-level keys equal every given value. */
6
+ listRuns(filter?: {
7
+ metadata?: Record<string, JsonValue>;
8
+ }): Promise<RunSummary[]>;
9
+ getRun(runId: string): Promise<RunSummary | undefined>;
10
+ getEvents(runId: string, options?: {
11
+ afterSequence?: number;
12
+ }): Promise<PlicoEvent[]>;
13
+ /** Returns run events in a thread, ordered by their durable insertion order. */
14
+ getThreadRunEvents?(threadId: string): Promise<PlicoEvent[]>;
15
+ /** Returns thread run events through the selected run's final durable position. */
16
+ getThreadRunEventsThrough?(threadId: string, runId: string): Promise<PlicoEvent[]>;
17
+ persistEvalReport(report: EvalReport): Promise<void>;
18
+ getLatestEvalReport(): Promise<EvalReport | undefined>;
19
+ }
20
+ export interface CreateSqliteEventStoreOptions {
21
+ databasePath: string;
22
+ /** Open an existing database without changing it. Adds no files unless it has a pending WAL. */
23
+ readOnly?: boolean;
24
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,15 @@
1
+ import type { JsonSchema, ToolDefinition } from "@plico-ai/contracts";
2
+ export type { JsonSchema, JsonSchemaObject, ToolApprovalPolicy, ToolArtifactContext, ToolArtifactFile, ToolDefinition, ToolHandlerContext, ToolInputSchema, ZodInputParseResult, ZodInputSchema, } from "@plico-ai/contracts";
3
+ export type ToolInputParseResult = {
4
+ success: true;
5
+ value: unknown;
6
+ } | {
7
+ success: false;
8
+ error: string;
9
+ };
10
+ export interface DeclaredTool extends Omit<ToolDefinition, "inputSchema"> {
11
+ source: string;
12
+ inputSchema: JsonSchema;
13
+ validateInput(input: unknown): Promise<string | undefined>;
14
+ parseInput(input: unknown): Promise<ToolInputParseResult>;
15
+ }