@fragno-dev/pi-harness 0.0.0-stage → 0.0.3

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 (140) hide show
  1. package/LICENSE.md +16 -0
  2. package/README.md +181 -2
  3. package/dist/browser/agent-harness-event-protocol-CuKubox1.js +666 -0
  4. package/dist/browser/agent-harness-event-protocol-CuKubox1.js.map +1 -0
  5. package/dist/browser/agent-harness-event-protocol-d6mH_9n3.d.ts +261 -0
  6. package/dist/browser/agent-harness-event-protocol-d6mH_9n3.d.ts.map +1 -0
  7. package/dist/browser/client/clients.d.ts +2 -0
  8. package/dist/browser/client/clients.js +2 -0
  9. package/dist/browser/client/pi-workflow-emission-stream.d.ts +13 -0
  10. package/dist/browser/client/pi-workflow-emission-stream.d.ts.map +1 -0
  11. package/dist/browser/client/pi-workflow-emission-stream.js +29 -0
  12. package/dist/browser/client/pi-workflow-emission-stream.js.map +1 -0
  13. package/dist/browser/client/react.d.ts +147 -0
  14. package/dist/browser/client/react.d.ts.map +1 -0
  15. package/dist/browser/client/react.js +187 -0
  16. package/dist/browser/client/react.js.map +1 -0
  17. package/dist/browser/client/solid.d.ts +150 -0
  18. package/dist/browser/client/solid.d.ts.map +1 -0
  19. package/dist/browser/client/solid.js +130 -0
  20. package/dist/browser/client/solid.js.map +1 -0
  21. package/dist/browser/client/svelte.d.ts +150 -0
  22. package/dist/browser/client/svelte.d.ts.map +1 -0
  23. package/dist/browser/client/svelte.js +132 -0
  24. package/dist/browser/client/svelte.js.map +1 -0
  25. package/dist/browser/client/vanilla.d.ts +177 -0
  26. package/dist/browser/client/vanilla.d.ts.map +1 -0
  27. package/dist/browser/client/vanilla.js +159 -0
  28. package/dist/browser/client/vanilla.js.map +1 -0
  29. package/dist/browser/client/vue.d.ts +150 -0
  30. package/dist/browser/client/vue.d.ts.map +1 -0
  31. package/dist/browser/client/vue.js +128 -0
  32. package/dist/browser/client/vue.js.map +1 -0
  33. package/dist/browser/client/workflow-lofi-session-projection.d.ts +17 -0
  34. package/dist/browser/client/workflow-lofi-session-projection.d.ts.map +1 -0
  35. package/dist/browser/client/workflow-lofi-session-projection.js +107 -0
  36. package/dist/browser/client/workflow-lofi-session-projection.js.map +1 -0
  37. package/dist/browser/clients-DYXj19je.d.ts +247 -0
  38. package/dist/browser/clients-DYXj19je.d.ts.map +1 -0
  39. package/dist/browser/clients-pIAk6ClP.js +1853 -0
  40. package/dist/browser/clients-pIAk6ClP.js.map +1 -0
  41. package/dist/browser/pi/context-usage.d.ts +20 -0
  42. package/dist/browser/pi/context-usage.d.ts.map +1 -0
  43. package/dist/browser/pi/context-usage.js +84 -0
  44. package/dist/browser/pi/context-usage.js.map +1 -0
  45. package/dist/browser/pi/harness/agent-harness-event-protocol.d.ts +2 -0
  46. package/dist/browser/pi/harness/agent-harness-event-protocol.js +2 -0
  47. package/dist/browser/pi/route-schemas.d.ts +2 -0
  48. package/dist/browser/pi/route-schemas.js +130 -0
  49. package/dist/browser/pi/route-schemas.js.map +1 -0
  50. package/dist/browser/pi/workflow-session-projection.d.ts +2 -0
  51. package/dist/browser/pi/workflow-session-projection.js +2 -0
  52. package/dist/browser/route-schemas-DQB5ZR1E.d.ts +109 -0
  53. package/dist/browser/route-schemas-DQB5ZR1E.d.ts.map +1 -0
  54. package/dist/browser/types-8q4RWFXT.js +23 -0
  55. package/dist/browser/types-8q4RWFXT.js.map +1 -0
  56. package/dist/browser/types-Dk856kV1.d.ts +527 -0
  57. package/dist/browser/types-Dk856kV1.d.ts.map +1 -0
  58. package/dist/browser/workflow-session-projection-CJ4MUkpJ.js +443 -0
  59. package/dist/browser/workflow-session-projection-CJ4MUkpJ.js.map +1 -0
  60. package/dist/browser/workflow-session-projection-Dj_a79GF.d.ts +93 -0
  61. package/dist/browser/workflow-session-projection-Dj_a79GF.d.ts.map +1 -0
  62. package/dist/node/pi/compact-command-outcome-projection.js +41 -0
  63. package/dist/node/pi/compact-command-outcome-projection.js.map +1 -0
  64. package/dist/node/pi/context-usage.d.ts +20 -0
  65. package/dist/node/pi/context-usage.d.ts.map +1 -0
  66. package/dist/node/pi/context-usage.js +84 -0
  67. package/dist/node/pi/context-usage.js.map +1 -0
  68. package/dist/node/pi/definition.d.ts +535 -0
  69. package/dist/node/pi/definition.d.ts.map +1 -0
  70. package/dist/node/pi/definition.js +71 -0
  71. package/dist/node/pi/definition.js.map +1 -0
  72. package/dist/node/pi/factory.d.ts +142 -0
  73. package/dist/node/pi/factory.d.ts.map +1 -0
  74. package/dist/node/pi/factory.js +22 -0
  75. package/dist/node/pi/factory.js.map +1 -0
  76. package/dist/node/pi/harness/agent-harness-event-protocol.d.ts +261 -0
  77. package/dist/node/pi/harness/agent-harness-event-protocol.d.ts.map +1 -0
  78. package/dist/node/pi/harness/agent-harness-event-protocol.js +588 -0
  79. package/dist/node/pi/harness/agent-harness-event-protocol.js.map +1 -0
  80. package/dist/node/pi/harness/json-value.js +82 -0
  81. package/dist/node/pi/harness/json-value.js.map +1 -0
  82. package/dist/node/pi/harness/pi-operation-completed.d.ts +16 -0
  83. package/dist/node/pi/harness/pi-operation-completed.d.ts.map +1 -0
  84. package/dist/node/pi/harness/pi-operation-completed.js +71 -0
  85. package/dist/node/pi/harness/pi-operation-completed.js.map +1 -0
  86. package/dist/node/pi/harness/session-storage.d.ts +62 -0
  87. package/dist/node/pi/harness/session-storage.d.ts.map +1 -0
  88. package/dist/node/pi/harness/session-storage.js +174 -0
  89. package/dist/node/pi/harness/session-storage.js.map +1 -0
  90. package/dist/node/pi/pi-jsonl-export.d.ts +11 -0
  91. package/dist/node/pi/pi-jsonl-export.d.ts.map +1 -0
  92. package/dist/node/pi/pi-jsonl-export.js +31 -0
  93. package/dist/node/pi/pi-jsonl-export.js.map +1 -0
  94. package/dist/node/pi/route-schemas.d.ts +109 -0
  95. package/dist/node/pi/route-schemas.d.ts.map +1 -0
  96. package/dist/node/pi/route-schemas.js +130 -0
  97. package/dist/node/pi/route-schemas.js.map +1 -0
  98. package/dist/node/pi/session-command-protocol.d.ts +14 -0
  99. package/dist/node/pi/session-command-protocol.d.ts.map +1 -0
  100. package/dist/node/pi/session-command-protocol.js +25 -0
  101. package/dist/node/pi/session-command-protocol.js.map +1 -0
  102. package/dist/node/pi/session-entry-projection.js +79 -0
  103. package/dist/node/pi/session-entry-projection.js.map +1 -0
  104. package/dist/node/pi/skills.d.ts +70 -0
  105. package/dist/node/pi/skills.d.ts.map +1 -0
  106. package/dist/node/pi/skills.js +150 -0
  107. package/dist/node/pi/skills.js.map +1 -0
  108. package/dist/node/pi/tools.d.ts +12 -0
  109. package/dist/node/pi/tools.d.ts.map +1 -0
  110. package/dist/node/pi/tools.js +8 -0
  111. package/dist/node/pi/tools.js.map +1 -0
  112. package/dist/node/pi/types.d.ts +165 -0
  113. package/dist/node/pi/types.d.ts.map +1 -0
  114. package/dist/node/pi/types.js +49 -0
  115. package/dist/node/pi/types.js.map +1 -0
  116. package/dist/node/pi/wait-for-command-step.js +46 -0
  117. package/dist/node/pi/wait-for-command-step.js.map +1 -0
  118. package/dist/node/pi/workflow-session-live-projection.js +220 -0
  119. package/dist/node/pi/workflow-session-live-projection.js.map +1 -0
  120. package/dist/node/pi/workflow-session-projection.d.ts +84 -0
  121. package/dist/node/pi/workflow-session-projection.d.ts.map +1 -0
  122. package/dist/node/pi/workflow-session-projection.js +100 -0
  123. package/dist/node/pi/workflow-session-projection.js.map +1 -0
  124. package/dist/node/pi/workflows/interactive-chat-workflow.d.ts +37 -0
  125. package/dist/node/pi/workflows/interactive-chat-workflow.d.ts.map +1 -0
  126. package/dist/node/pi/workflows/interactive-chat-workflow.js +219 -0
  127. package/dist/node/pi/workflows/interactive-chat-workflow.js.map +1 -0
  128. package/dist/node/pi/workflows/workflow-agent-harness.d.ts +142 -0
  129. package/dist/node/pi/workflows/workflow-agent-harness.d.ts.map +1 -0
  130. package/dist/node/pi/workflows/workflow-agent-harness.js +450 -0
  131. package/dist/node/pi/workflows/workflow-agent-harness.js.map +1 -0
  132. package/dist/node/routes.d.ts +631 -0
  133. package/dist/node/routes.d.ts.map +1 -0
  134. package/dist/node/routes.js +355 -0
  135. package/dist/node/routes.js.map +1 -0
  136. package/dist/node/schema.d.ts +5 -0
  137. package/dist/node/schema.d.ts.map +1 -0
  138. package/dist/node/schema.js +7 -0
  139. package/dist/node/schema.js.map +1 -0
  140. package/package.json +175 -3
@@ -0,0 +1,150 @@
1
+ import { Type } from "typebox";
2
+ //#region src/pi/skills.ts
3
+ const escapeXml = (value) => value.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;").replaceAll("\"", "&quot;").replaceAll("'", "&apos;");
4
+ const isPiSkillDefinitionArray = (skills) => Array.isArray(skills);
5
+ const skillCatalogEntries = (skills) => (isPiSkillDefinitionArray(skills) ? skills : Object.values(skills)).toSorted((left, right) => left.name.localeCompare(right.name));
6
+ const renderPiSkillCatalogXml = (skills) => {
7
+ const entries = skillCatalogEntries(skills);
8
+ if (entries.length === 0) return "";
9
+ return `<available_skills>
10
+ ${entries.map((skill) => ` <skill>
11
+ <name>${escapeXml(skill.name)}</name>
12
+ <description>${escapeXml(skill.description)}</description>
13
+ </skill>`).join("\n")}
14
+ </available_skills>`;
15
+ };
16
+ const renderSkillResourceXml = (resource) => {
17
+ return ` <file>\n${[
18
+ ` <path>${escapeXml(resource.path)}</path>`,
19
+ resource.description === void 0 ? void 0 : ` <description>${escapeXml(resource.description)}</description>`,
20
+ resource.mimeType === void 0 ? void 0 : ` <mimeType>${escapeXml(resource.mimeType)}</mimeType>`
21
+ ].filter((field) => field !== void 0).join("\n")}\n </file>`;
22
+ };
23
+ const inferSkillDirectory = (skill) => {
24
+ if (skill.directory !== void 0) return skill.directory;
25
+ if (skill.location === void 0) return;
26
+ const normalizedLocation = skill.location.replaceAll("\\", "/");
27
+ const lastSlash = normalizedLocation.lastIndexOf("/");
28
+ if (lastSlash === -1) return;
29
+ return normalizedLocation.slice(0, lastSlash);
30
+ };
31
+ const renderPiSkillActivationXml = (skill) => {
32
+ const directory = inferSkillDirectory(skill);
33
+ const sections = [
34
+ `<name>${escapeXml(skill.name)}</name>`,
35
+ `<description>${escapeXml(skill.description)}</description>`,
36
+ skill.body === void 0 ? void 0 : `<body>\n${escapeXml(skill.body)}\n</body>`,
37
+ directory === void 0 ? void 0 : `<directory>${escapeXml(directory)}</directory>`,
38
+ skill.location === void 0 ? void 0 : `<location>${escapeXml(skill.location)}</location>`,
39
+ skill.resources?.length ? `<resource_path_note>Resource file paths are relative to the skill itself.</resource_path_note>` : void 0,
40
+ skill.resources?.length ? `<skill_resources>\n${skill.resources.map(renderSkillResourceXml).join("\n")}\n</skill_resources>` : void 0
41
+ ].filter((section) => section !== void 0);
42
+ return `<skill_content name="${escapeXml(skill.name)}">\n${sections.join("\n")}\n</skill_content>`;
43
+ };
44
+ const renderPiSkillInvocationContext = (skill, options = {}) => {
45
+ const skillInvocationXml = renderPiSkillActivationXml(skill);
46
+ if (!options.extraUserInstructions) return skillInvocationXml;
47
+ return `${skillInvocationXml}\n\n${options.extraUserInstructions}`;
48
+ };
49
+ const findSkill = (skills, name) => {
50
+ if (isPiSkillDefinitionArray(skills)) return skills.find((skill) => skill.name === name);
51
+ return skills[name];
52
+ };
53
+ const skillActivationParameters = Type.Object({ name: Type.String() });
54
+ const createPiSkillActivationTool = (skills, options = {}) => ({
55
+ name: options.name ?? "activate_skill",
56
+ label: options.label ?? "Activate skill",
57
+ description: options.description ?? "Load the full instructions for a registered Pi skill by name.",
58
+ parameters: skillActivationParameters,
59
+ async execute(_toolCallId, params) {
60
+ const skill = findSkill(skills, params.name);
61
+ if (!skill) return {
62
+ content: [{
63
+ type: "text",
64
+ text: `Skill '${params.name}' was not found.`
65
+ }],
66
+ details: {
67
+ found: false,
68
+ name: params.name
69
+ },
70
+ isError: true
71
+ };
72
+ return {
73
+ content: [{
74
+ type: "text",
75
+ text: renderPiSkillActivationXml(skill)
76
+ }],
77
+ details: {
78
+ found: true,
79
+ name: skill.name,
80
+ resourceCount: skill.resources?.length ?? 0
81
+ }
82
+ };
83
+ }
84
+ });
85
+ var PiSkillDefinitionBuilder = class {
86
+ #name;
87
+ #description;
88
+ #body;
89
+ #location;
90
+ #directory;
91
+ #resources = [];
92
+ #metadata;
93
+ constructor(name) {
94
+ this.#name = name;
95
+ }
96
+ description(description) {
97
+ this.#description = description;
98
+ return this;
99
+ }
100
+ body(body) {
101
+ this.#body = body;
102
+ return this;
103
+ }
104
+ location(location) {
105
+ this.#location = location;
106
+ return this;
107
+ }
108
+ directory(directory) {
109
+ this.#directory = directory;
110
+ return this;
111
+ }
112
+ resource(path, resource = {}) {
113
+ this.#resources.push({
114
+ ...resource,
115
+ path
116
+ });
117
+ return this;
118
+ }
119
+ resources(resources) {
120
+ this.#resources = [...resources];
121
+ return this;
122
+ }
123
+ metadata(metadata) {
124
+ this.#metadata = { ...metadata };
125
+ return this;
126
+ }
127
+ metadataValue(key, value) {
128
+ this.#metadata = {
129
+ ...this.#metadata,
130
+ [key]: value
131
+ };
132
+ return this;
133
+ }
134
+ build() {
135
+ if (!this.#description) throw new Error(`Skill '${this.#name}' must define a description.`);
136
+ return {
137
+ name: this.#name,
138
+ description: this.#description,
139
+ ...this.#body === void 0 ? {} : { body: this.#body },
140
+ ...this.#location === void 0 ? {} : { location: this.#location },
141
+ ...this.#directory === void 0 ? {} : { directory: this.#directory },
142
+ ...this.#resources.length === 0 ? {} : { resources: [...this.#resources] },
143
+ ...this.#metadata === void 0 ? {} : { metadata: { ...this.#metadata } }
144
+ };
145
+ }
146
+ };
147
+ //#endregion
148
+ export { PiSkillDefinitionBuilder, createPiSkillActivationTool, renderPiSkillCatalogXml, renderPiSkillInvocationContext };
149
+
150
+ //# sourceMappingURL=skills.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"skills.js","names":["#name","#description","#body","#location","#directory","#resources","#metadata"],"sources":["../../../src/pi/skills.ts"],"sourcesContent":["import { Type } from \"typebox\";\n\nimport type { PiToolDefinition } from \"./types\";\n\nexport type PiSkillResource = {\n path: string;\n description?: string;\n content?: string;\n mimeType?: string;\n metadata?: Record<string, unknown>;\n};\n\nexport type PiSkillDefinition = {\n name: string;\n description: string;\n body?: string;\n location?: string;\n directory?: string;\n resources?: readonly PiSkillResource[];\n metadata?: Record<string, unknown>;\n};\n\nexport type PiSkillDefinitionInput = Omit<PiSkillDefinition, \"name\"> & {\n name?: string;\n};\n\nexport type PiSkillRegistry = Record<string, PiSkillDefinition>;\n\nexport type PiAgentSkillSelection = readonly string[] | \"all\";\n\nexport type PiSkillResolverContext = {\n workflowName: string;\n sessionId: string;\n turnId: string;\n};\n\nexport type PiSkillRegistryResolver = (\n context: PiSkillResolverContext,\n) => PiSkillRegistry | Promise<PiSkillRegistry>;\n\nexport type PiSkillRegistrySource = PiSkillRegistry | PiSkillRegistryResolver;\n\nexport type PiSkillCatalogXmlInput = PiSkillRegistry | readonly PiSkillDefinition[];\n\nexport type PiSkillActivationDetails =\n | {\n found: true;\n name: string;\n resourceCount: number;\n }\n | {\n found: false;\n name: string;\n };\n\nexport type CreatePiSkillActivationToolOptions = {\n name?: string;\n label?: string;\n description?: string;\n};\n\nexport type PiSkillInvocationContextOptions = {\n extraUserInstructions?: string;\n};\n\nconst escapeXml = (value: string) =>\n value\n .replaceAll(\"&\", \"&amp;\")\n .replaceAll(\"<\", \"&lt;\")\n .replaceAll(\">\", \"&gt;\")\n .replaceAll('\"', \"&quot;\")\n .replaceAll(\"'\", \"&apos;\");\n\nconst isPiSkillDefinitionArray = (\n skills: PiSkillCatalogXmlInput,\n): skills is readonly PiSkillDefinition[] => Array.isArray(skills);\n\nconst skillCatalogEntries = (skills: PiSkillCatalogXmlInput) =>\n (isPiSkillDefinitionArray(skills) ? skills : Object.values(skills)).toSorted((left, right) =>\n left.name.localeCompare(right.name),\n );\n\nexport const renderPiSkillCatalogXml = (skills: PiSkillCatalogXmlInput): string => {\n const entries = skillCatalogEntries(skills);\n if (entries.length === 0) {\n return \"\";\n }\n\n const skillXml = entries\n .map(\n (skill) => ` <skill>\n <name>${escapeXml(skill.name)}</name>\n <description>${escapeXml(skill.description)}</description>\n </skill>`,\n )\n .join(\"\\n\");\n\n return `<available_skills>\n${skillXml}\n</available_skills>`;\n};\n\nconst renderSkillResourceXml = (resource: PiSkillResource) => {\n const fields = [\n ` <path>${escapeXml(resource.path)}</path>`,\n resource.description === undefined\n ? undefined\n : ` <description>${escapeXml(resource.description)}</description>`,\n resource.mimeType === undefined\n ? undefined\n : ` <mimeType>${escapeXml(resource.mimeType)}</mimeType>`,\n ].filter((field): field is string => field !== undefined);\n\n return ` <file>\\n${fields.join(\"\\n\")}\\n </file>`;\n};\n\nconst inferSkillDirectory = (skill: PiSkillDefinition) => {\n if (skill.directory !== undefined) {\n return skill.directory;\n }\n if (skill.location === undefined) {\n return undefined;\n }\n\n const normalizedLocation = skill.location.replaceAll(\"\\\\\", \"/\");\n const lastSlash = normalizedLocation.lastIndexOf(\"/\");\n if (lastSlash === -1) {\n return undefined;\n }\n return normalizedLocation.slice(0, lastSlash);\n};\n\nconst renderPiSkillActivationXml = (skill: PiSkillDefinition): string => {\n const directory = inferSkillDirectory(skill);\n const sections = [\n `<name>${escapeXml(skill.name)}</name>`,\n `<description>${escapeXml(skill.description)}</description>`,\n skill.body === undefined ? undefined : `<body>\\n${escapeXml(skill.body)}\\n</body>`,\n directory === undefined ? undefined : `<directory>${escapeXml(directory)}</directory>`,\n skill.location === undefined ? undefined : `<location>${escapeXml(skill.location)}</location>`,\n skill.resources?.length\n ? `<resource_path_note>Resource file paths are relative to the skill itself.</resource_path_note>`\n : undefined,\n skill.resources?.length\n ? `<skill_resources>\\n${skill.resources.map(renderSkillResourceXml).join(\"\\n\")}\\n</skill_resources>`\n : undefined,\n ].filter((section): section is string => section !== undefined);\n\n return `<skill_content name=\"${escapeXml(skill.name)}\">\\n${sections.join(\"\\n\")}\\n</skill_content>`;\n};\n\nexport const renderPiSkillInvocationContext = (\n skill: PiSkillDefinition,\n options: PiSkillInvocationContextOptions = {},\n): string => {\n const skillInvocationXml = renderPiSkillActivationXml(skill);\n if (!options.extraUserInstructions) {\n return skillInvocationXml;\n }\n\n return `${skillInvocationXml}\\n\\n${options.extraUserInstructions}`;\n};\n\nconst findSkill = (skills: PiSkillCatalogXmlInput, name: string) => {\n if (isPiSkillDefinitionArray(skills)) {\n return skills.find((skill) => skill.name === name);\n }\n return skills[name];\n};\n\nconst skillActivationParameters = Type.Object({ name: Type.String() });\n\nexport const createPiSkillActivationTool = (\n skills: PiSkillCatalogXmlInput,\n options: CreatePiSkillActivationToolOptions = {},\n): PiToolDefinition<typeof skillActivationParameters, PiSkillActivationDetails> => ({\n name: options.name ?? \"activate_skill\",\n label: options.label ?? \"Activate skill\",\n description:\n options.description ?? \"Load the full instructions for a registered Pi skill by name.\",\n parameters: skillActivationParameters,\n async execute(_toolCallId, params) {\n const skill = findSkill(skills, params.name);\n if (!skill) {\n return {\n content: [{ type: \"text\", text: `Skill '${params.name}' was not found.` }],\n details: { found: false, name: params.name },\n isError: true,\n };\n }\n\n return {\n content: [{ type: \"text\", text: renderPiSkillActivationXml(skill) }],\n details: {\n found: true,\n name: skill.name,\n resourceCount: skill.resources?.length ?? 0,\n },\n };\n },\n});\n\nexport class PiSkillDefinitionBuilder<TName extends string = string> {\n readonly #name: TName;\n #description: string | undefined;\n #body: string | undefined;\n #location: string | undefined;\n #directory: string | undefined;\n #resources: PiSkillResource[] = [];\n #metadata: Record<string, unknown> | undefined;\n\n constructor(name: TName) {\n this.#name = name;\n }\n\n description(description: string): this {\n this.#description = description;\n return this;\n }\n\n body(body: string): this {\n this.#body = body;\n return this;\n }\n\n location(location: string): this {\n this.#location = location;\n return this;\n }\n\n directory(directory: string): this {\n this.#directory = directory;\n return this;\n }\n\n resource(path: string, resource: Omit<PiSkillResource, \"path\"> = {}): this {\n this.#resources.push({ ...resource, path });\n return this;\n }\n\n resources(resources: readonly PiSkillResource[]): this {\n this.#resources = [...resources];\n return this;\n }\n\n metadata(metadata: Record<string, unknown>): this {\n this.#metadata = { ...metadata };\n return this;\n }\n\n metadataValue(key: string, value: unknown): this {\n this.#metadata = { ...this.#metadata, [key]: value };\n return this;\n }\n\n build(): PiSkillDefinition {\n if (!this.#description) {\n throw new Error(`Skill '${this.#name}' must define a description.`);\n }\n\n return {\n name: this.#name,\n description: this.#description,\n ...(this.#body === undefined ? {} : { body: this.#body }),\n ...(this.#location === undefined ? {} : { location: this.#location }),\n ...(this.#directory === undefined ? {} : { directory: this.#directory }),\n ...(this.#resources.length === 0 ? {} : { resources: [...this.#resources] }),\n ...(this.#metadata === undefined ? {} : { metadata: { ...this.#metadata } }),\n };\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,12 @@
1
+ import { AnyPiToolDefinition, PiToolDefinition, PiToolDetailsFromResultSchema, PiToolResultSchema } from "./types.js";
2
+ import { TSchema } from "typebox";
3
+ //#region src/pi/tools.d.ts
4
+ declare function definePiTool<TParameters extends TSchema, TResultSchema extends PiToolResultSchema<unknown>>(tool: PiToolDefinition<TParameters, PiToolDetailsFromResultSchema<TResultSchema>, TResultSchema> & {
5
+ resultSchema: TResultSchema;
6
+ }): PiToolDefinition<TParameters, PiToolDetailsFromResultSchema<TResultSchema>, TResultSchema>;
7
+ declare function definePiTool<TParameters extends TSchema, TDetails>(tool: PiToolDefinition<TParameters, TDetails> & {
8
+ resultSchema?: undefined;
9
+ }): PiToolDefinition<TParameters, TDetails>;
10
+ //#endregion
11
+ export { type AnyPiToolDefinition, type PiToolDefinition, type PiToolDetailsFromResultSchema, type PiToolResultSchema, definePiTool };
12
+ //# sourceMappingURL=tools.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.d.ts","names":[],"sources":["../../../src/pi/tools.ts"],"mappings":";;;iBASgB,aACd,oBAAoB,SACpB,sBAAsB,6BAEtB,MAAM,iBACJ,aACA,8BAA8B,gBAC9B;EAEA,cAAc;IAEf,iBAAiB,aAAa,8BAA8B,gBAAgB;iBAC/D,aAAa,oBAAoB,SAAe,UAC9D,MAAM,iBAAiB,aAAa;EAAc;IACjD,iBAAiB,aAAa"}
@@ -0,0 +1,8 @@
1
+ //#region src/pi/tools.ts
2
+ function definePiTool(tool) {
3
+ return tool;
4
+ }
5
+ //#endregion
6
+ export { definePiTool };
7
+
8
+ //# sourceMappingURL=tools.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tools.js","names":[],"sources":["../../../src/pi/tools.ts"],"sourcesContent":["import type { TSchema as TypeBoxSchema } from \"typebox\";\n\nimport type {\n AnyPiToolDefinition,\n PiToolDefinition,\n PiToolDetailsFromResultSchema,\n PiToolResultSchema,\n} from \"./types\";\n\nexport function definePiTool<\n TParameters extends TypeBoxSchema,\n TResultSchema extends PiToolResultSchema<unknown>,\n>(\n tool: PiToolDefinition<\n TParameters,\n PiToolDetailsFromResultSchema<TResultSchema>,\n TResultSchema\n > & {\n resultSchema: TResultSchema;\n },\n): PiToolDefinition<TParameters, PiToolDetailsFromResultSchema<TResultSchema>, TResultSchema>;\nexport function definePiTool<TParameters extends TypeBoxSchema, TDetails>(\n tool: PiToolDefinition<TParameters, TDetails> & { resultSchema?: undefined },\n): PiToolDefinition<TParameters, TDetails>;\nexport function definePiTool(tool: AnyPiToolDefinition): AnyPiToolDefinition {\n return tool;\n}\n\nexport type {\n AnyPiToolDefinition,\n PiToolDefinition,\n PiToolDetailsFromResultSchema,\n PiToolResultSchema,\n} from \"./types\";\n"],"mappings":";AAwBA,SAAgB,aAAa,MAAgD;CAC3E,OAAO;AACT"}
@@ -0,0 +1,165 @@
1
+ import { PiHarnessFrontendAgentMessage } from "./harness/agent-harness-event-protocol.js";
2
+ import { PiHarnessOperation } from "./workflows/workflow-agent-harness.js";
3
+ import { HookContext } from "@fragno-dev/db";
4
+ import { AgentTool, AgentToolResult } from "@earendil-works/pi-agent-core";
5
+ import { InstanceStatus, WorkflowRegistryEntry } from "@fragno-dev/workflows/workflow";
6
+ import { Static, TSchema } from "typebox";
7
+ import { AssistantMessage } from "@earendil-works/pi-ai";
8
+ import { StandardSchemaV1 } from "@fragno-dev/core/api";
9
+ //#region src/pi/types.d.ts
10
+ type PiLoggerConfig = {
11
+ enabled?: boolean;
12
+ level?: "off" | "error" | "warn" | "info" | "debug";
13
+ };
14
+ type PiWorkflowStatus = InstanceStatus["status"];
15
+ type PiSessionMetadata = Record<string, unknown>;
16
+ type PiSession = {
17
+ id: string;
18
+ name: string | null;
19
+ metadata: PiSessionMetadata | null;
20
+ workflowName: string;
21
+ createdAt: Date;
22
+ updatedAt: Date;
23
+ };
24
+ declare class PiSessionDataUnavailableError extends Error {
25
+ readonly workflowName: string;
26
+ readonly sessionId: string;
27
+ readonly code = "PI_SESSION_DATA_UNAVAILABLE";
28
+ constructor(workflowName: string, sessionId: string);
29
+ }
30
+ declare class PiSessionDataIntegrityError extends Error {
31
+ readonly workflowName: string;
32
+ readonly sessionId: string;
33
+ readonly code = "PI_SESSION_DATA_INTEGRITY_ERROR";
34
+ constructor(workflowName: string, sessionId: string, cause: unknown);
35
+ }
36
+ declare const projectPiSessionFromWorkflowInstance: (instance: {
37
+ id: string;
38
+ workflowName: string;
39
+ params: unknown;
40
+ createdAt: Date;
41
+ updatedAt: Date;
42
+ }) => PiSession | null;
43
+ type PiOperationDetails = {
44
+ actor: unknown;
45
+ workflowName: string;
46
+ sessionId: string;
47
+ metadata: PiSessionMetadata | null;
48
+ stepName: string;
49
+ operationId: string;
50
+ operation: PiHarnessOperation["kind"];
51
+ };
52
+ type PiOperationCompletedHookPayload = PiOperationDetails & {
53
+ /**
54
+ * Model calls exposed by Pi as assistant messages during this operation.
55
+ *
56
+ * Compact operations and tree navigation with summarization are not included yet because Pi
57
+ * does not expose their internal model calls as first-class harness events.
58
+ */
59
+ modelCalls: Array<Pick<AssistantMessage, "api" | "provider" | "model" | "responseModel" | "responseId" | "usage" | "stopReason" | "timestamp">>;
60
+ usage: AssistantMessage["usage"];
61
+ };
62
+ /** Maximum total Base64 characters persisted in one Pi command event. */
63
+ declare const MAX_PI_COMMAND_IMAGE_DATA_LENGTH: number;
64
+ declare const PI_SESSION_COMMAND_STEP_PREFIX = "command:";
65
+ type PiPromptInput = {
66
+ text: string;
67
+ images?: Array<{
68
+ type: "image";
69
+ data: string;
70
+ mimeType: string;
71
+ }>;
72
+ };
73
+ type PiCompactCommandOutcome = {
74
+ kind: "compact";
75
+ commandId: string;
76
+ status: "succeeded";
77
+ } | {
78
+ kind: "compact";
79
+ commandId: string;
80
+ status: "rejected";
81
+ code: "nothing_to_compact" | "compaction_failed";
82
+ message: string;
83
+ };
84
+ type PiSessionCommandPayload = {
85
+ commandId: string;
86
+ kind: "prompt";
87
+ input: PiPromptInput;
88
+ } | {
89
+ commandId: string;
90
+ kind: "skill";
91
+ input: {
92
+ name: string;
93
+ additionalInstructions?: string;
94
+ };
95
+ } | {
96
+ commandId: string;
97
+ kind: "promptFromTemplate";
98
+ input: {
99
+ name: string;
100
+ args?: string[];
101
+ };
102
+ } | {
103
+ commandId: string;
104
+ kind: "compact";
105
+ input: {
106
+ customInstructions?: string;
107
+ };
108
+ } | {
109
+ commandId: string;
110
+ kind: "abort";
111
+ reason?: string;
112
+ } | {
113
+ commandId: string;
114
+ kind: "steer";
115
+ input: PiPromptInput;
116
+ } | {
117
+ commandId: string;
118
+ kind: "followUp";
119
+ input: PiPromptInput;
120
+ };
121
+ type PiAgentStateSnapshot = {
122
+ messages: PiHarnessFrontendAgentMessage[];
123
+ };
124
+ type PiSessionDetail = PiSession & {
125
+ workflow: {
126
+ status: PiWorkflowStatus;
127
+ error?: {
128
+ name: string;
129
+ message: string;
130
+ };
131
+ output?: unknown;
132
+ };
133
+ agent: {
134
+ state: PiAgentStateSnapshot;
135
+ };
136
+ };
137
+ type PiToolResultSchema<TDetails> = StandardSchemaV1<unknown, TDetails> | TSchema;
138
+ type PiToolDetailsFromResultSchema<TResultSchema> = TResultSchema extends StandardSchemaV1<unknown, infer TDetails> ? TDetails : TResultSchema extends TSchema ? Static<TResultSchema> : unknown;
139
+ type PiToolDefinition<TParameters extends TSchema = TSchema, TDetails = unknown, TResultSchema extends PiToolResultSchema<TDetails> | undefined = PiToolResultSchema<TDetails> | undefined> = AgentTool<TParameters, TDetails> & {
140
+ name: string;
141
+ resultSchema?: TResultSchema;
142
+ handoff?: boolean;
143
+ };
144
+ type AnyPiToolDefinition = Omit<AgentTool<TSchema, unknown>, "execute"> & {
145
+ name: string;
146
+ resultSchema?: PiToolResultSchema<unknown>;
147
+ handoff?: boolean;
148
+ execute: (toolCallId: string, params: any, signal?: AbortSignal, onUpdate?: (partialResult: AgentToolResult<any>) => void) => Promise<AgentToolResult<any>>;
149
+ };
150
+ interface PiFragmentConfig {
151
+ workflows?: WorkflowRegistryEntry[];
152
+ /**
153
+ * Called through a durable hook after a harness operation commits a terminal outcome.
154
+ *
155
+ * Usage reporting currently excludes compact operations and tree navigation with summarization.
156
+ */
157
+ onOperationCompleted?: (payload: PiOperationCompletedHookPayload, context: HookContext) => Promise<void> | void;
158
+ /**
159
+ * Optional logging config for internal pi-harness diagnostics.
160
+ */
161
+ logging?: PiLoggerConfig;
162
+ }
163
+ //#endregion
164
+ export { AnyPiToolDefinition, MAX_PI_COMMAND_IMAGE_DATA_LENGTH, PI_SESSION_COMMAND_STEP_PREFIX, PiAgentStateSnapshot, PiCompactCommandOutcome, PiFragmentConfig, PiLoggerConfig, PiOperationCompletedHookPayload, PiOperationDetails, PiPromptInput, PiSession, PiSessionCommandPayload, PiSessionDataIntegrityError, PiSessionDataUnavailableError, PiSessionDetail, PiSessionMetadata, PiToolDefinition, PiToolDetailsFromResultSchema, PiToolResultSchema, PiWorkflowStatus, projectPiSessionFromWorkflowInstance };
165
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","names":[],"sources":["../../../src/pi/types.ts"],"mappings":";;;;;;;;;KAaY;EACV;EACA;;KAGU,mBAAmB;KAEnB,oBAAoB;KAEpB;EACV;EACA;EACA,UAAU;EACV;EACA,WAAW;EACX,WAAW;;cAUA,sCAAsC;WAItC;WACA;WAJF;cAGE,sBACA;;cAOA,oCAAoC;WAIpC;WACA;WAJF;cAGE,sBACA,mBACT;;cAOS,uCAAwC;EACnD;EACA;EACA;EACA,WAAW;EACX,WAAW;MACT;KA0BQ;EACV;EACA;EACA;EACA,UAAU;EACV;EACA;EACA,WAAW;;KAGD,kCAAkC;;;;;;;EAO5C,YAAY,MACV,KACE;EAWJ,OAAO;;;cAII;cAEA;KAED;EACV;EACA,SAAS;IAAQ;IAAe;IAAc;;;KAGpC;EAEN;EACA;EACA;;EAGA;EACA;EACA;EACA;EACA;;KAGM;EACN;EAAmB;EAAgB,OAAO;;EAC1C;EAAmB;EAAe;IAAS;IAAc;;;EACzD;EAAmB;EAA4B;IAAS;IAAc;;;EACtE;EAAmB;EAAiB;IAAS;;;EAC7C;EAAmB;EAAe;;EAClC;EAAmB;EAAe,OAAO;;EACzC;EAAmB;EAAkB,OAAO;;KAEtC;EACV,UAAU;;KAGA,kBAAkB;EAC5B;IACE,QAAQ;IACR;MAAU;MAAc;;IACxB;;EAEF;IACE,OAAO;;;KAIC,mBAAmB,YAAY,0BAA0B,YAAY;KAErE,8BAA8B,iBACxC,sBAAsB,gCAAgC,YAClD,WACA,sBAAsB,UACpB,OAAO;KAGH,iBACV,oBAAoB,UAAgB,SACpC,oBACA,sBAAsB,mBAAmB,wBACrC,mBAAmB,yBAErB,UAAU,aAAa;EACzB;EACA,eAAe;EACf;;KAGU,sBAAsB,KAAK,UAAU;EAC/C;EACA,eAAe;EACf;EACA,UACE,oBAEA,aACA,SAAS,aAET,YAAY,eAAe,kCAExB,QAAQ;;UAGE;EACf,YAAY;;;;;;EAMZ,wBACE,SAAS,iCACT,SAAS,gBACN;;;;EAIL,UAAU"}
@@ -0,0 +1,49 @@
1
+ import { z } from "zod";
2
+ //#region src/pi/types.ts
3
+ const piSessionWorkflowParamsSchema = z.object({
4
+ metadata: z.record(z.string(), z.unknown()).optional(),
5
+ __piSession: z.object({ name: z.string().nullable() })
6
+ });
7
+ var PiSessionDataUnavailableError = class extends Error {
8
+ workflowName;
9
+ sessionId;
10
+ code = "PI_SESSION_DATA_UNAVAILABLE";
11
+ constructor(workflowName, sessionId) {
12
+ super(`Workflow ${workflowName}/${sessionId} does not contain Pi session data.`);
13
+ this.workflowName = workflowName;
14
+ this.sessionId = sessionId;
15
+ this.name = "PiSessionDataUnavailableError";
16
+ }
17
+ };
18
+ var PiSessionDataIntegrityError = class extends Error {
19
+ workflowName;
20
+ sessionId;
21
+ code = "PI_SESSION_DATA_INTEGRITY_ERROR";
22
+ constructor(workflowName, sessionId, cause) {
23
+ super(`Persisted Pi session data for ${workflowName}/${sessionId} is invalid.`, { cause });
24
+ this.workflowName = workflowName;
25
+ this.sessionId = sessionId;
26
+ this.name = "PiSessionDataIntegrityError";
27
+ }
28
+ };
29
+ const projectPiSessionFromWorkflowInstance = (instance) => {
30
+ const persistedParams = instance.params;
31
+ if (typeof persistedParams !== "object" || persistedParams === null || Array.isArray(persistedParams) || !Object.hasOwn(persistedParams, "__piSession")) return null;
32
+ const params = piSessionWorkflowParamsSchema.safeParse(persistedParams);
33
+ if (!params.success) throw new PiSessionDataIntegrityError(instance.workflowName, instance.id, params.error);
34
+ return {
35
+ id: instance.id,
36
+ name: params.data.__piSession.name,
37
+ metadata: params.data.metadata ?? null,
38
+ workflowName: instance.workflowName,
39
+ createdAt: instance.createdAt,
40
+ updatedAt: instance.updatedAt
41
+ };
42
+ };
43
+ /** Maximum total Base64 characters persisted in one Pi command event. */
44
+ const MAX_PI_COMMAND_IMAGE_DATA_LENGTH = 8 * 1024 * 1024;
45
+ const PI_SESSION_COMMAND_STEP_PREFIX = "command:";
46
+ //#endregion
47
+ export { MAX_PI_COMMAND_IMAGE_DATA_LENGTH, PI_SESSION_COMMAND_STEP_PREFIX, PiSessionDataIntegrityError, PiSessionDataUnavailableError, projectPiSessionFromWorkflowInstance };
48
+
49
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","names":[],"sources":["../../../src/pi/types.ts"],"sourcesContent":["import type { StandardSchemaV1 } from \"@fragno-dev/core/api\";\nimport type { InstanceStatus, WorkflowRegistryEntry } from \"@fragno-dev/workflows/workflow\";\nimport type { Static, TSchema as TypeBoxSchema } from \"typebox\";\nimport { z } from \"zod\";\n\nimport type { HookContext } from \"@fragno-dev/db\";\n\nimport type { AgentTool, AgentToolResult } from \"@earendil-works/pi-agent-core\";\nimport type { AssistantMessage } from \"@earendil-works/pi-ai\";\n\nimport type { PiHarnessFrontendAgentMessage } from \"./harness/agent-harness-event-protocol\";\nimport type { PiHarnessOperation } from \"./workflows/workflow-agent-harness\";\n\nexport type PiLoggerConfig = {\n enabled?: boolean;\n level?: \"off\" | \"error\" | \"warn\" | \"info\" | \"debug\";\n};\n\nexport type PiWorkflowStatus = InstanceStatus[\"status\"];\n\nexport type PiSessionMetadata = Record<string, unknown>;\n\nexport type PiSession = {\n id: string;\n name: string | null;\n metadata: PiSessionMetadata | null;\n workflowName: string;\n createdAt: Date;\n updatedAt: Date;\n};\n\nconst piSessionWorkflowParamsSchema = z.object({\n metadata: z.record(z.string(), z.unknown()).optional(),\n __piSession: z.object({\n name: z.string().nullable(),\n }),\n});\n\nexport class PiSessionDataUnavailableError extends Error {\n readonly code = \"PI_SESSION_DATA_UNAVAILABLE\";\n\n constructor(\n readonly workflowName: string,\n readonly sessionId: string,\n ) {\n super(`Workflow ${workflowName}/${sessionId} does not contain Pi session data.`);\n this.name = \"PiSessionDataUnavailableError\";\n }\n}\n\nexport class PiSessionDataIntegrityError extends Error {\n readonly code = \"PI_SESSION_DATA_INTEGRITY_ERROR\";\n\n constructor(\n readonly workflowName: string,\n readonly sessionId: string,\n cause: unknown,\n ) {\n super(`Persisted Pi session data for ${workflowName}/${sessionId} is invalid.`, { cause });\n this.name = \"PiSessionDataIntegrityError\";\n }\n}\n\nexport const projectPiSessionFromWorkflowInstance = (instance: {\n id: string;\n workflowName: string;\n params: unknown;\n createdAt: Date;\n updatedAt: Date;\n}): PiSession | null => {\n const persistedParams = instance.params;\n if (\n typeof persistedParams !== \"object\" ||\n persistedParams === null ||\n Array.isArray(persistedParams) ||\n !Object.hasOwn(persistedParams, \"__piSession\")\n ) {\n return null;\n }\n\n const params = piSessionWorkflowParamsSchema.safeParse(persistedParams);\n if (!params.success) {\n throw new PiSessionDataIntegrityError(instance.workflowName, instance.id, params.error);\n }\n\n return {\n id: instance.id,\n name: params.data.__piSession.name,\n metadata: params.data.metadata ?? null,\n workflowName: instance.workflowName,\n createdAt: instance.createdAt,\n updatedAt: instance.updatedAt,\n };\n};\n\nexport type PiOperationDetails = {\n actor: unknown;\n workflowName: string;\n sessionId: string;\n metadata: PiSessionMetadata | null;\n stepName: string;\n operationId: string;\n operation: PiHarnessOperation[\"kind\"];\n};\n\nexport type PiOperationCompletedHookPayload = PiOperationDetails & {\n /**\n * Model calls exposed by Pi as assistant messages during this operation.\n *\n * Compact operations and tree navigation with summarization are not included yet because Pi\n * does not expose their internal model calls as first-class harness events.\n */\n modelCalls: Array<\n Pick<\n AssistantMessage,\n | \"api\"\n | \"provider\"\n | \"model\"\n | \"responseModel\"\n | \"responseId\"\n | \"usage\"\n | \"stopReason\"\n | \"timestamp\"\n >\n >;\n usage: AssistantMessage[\"usage\"];\n};\n\n/** Maximum total Base64 characters persisted in one Pi command event. */\nexport const MAX_PI_COMMAND_IMAGE_DATA_LENGTH = 8 * 1024 * 1024;\n\nexport const PI_SESSION_COMMAND_STEP_PREFIX = \"command:\";\n\nexport type PiPromptInput = {\n text: string;\n images?: Array<{ type: \"image\"; data: string; mimeType: string }>;\n};\n\nexport type PiCompactCommandOutcome =\n | {\n kind: \"compact\";\n commandId: string;\n status: \"succeeded\";\n }\n | {\n kind: \"compact\";\n commandId: string;\n status: \"rejected\";\n code: \"nothing_to_compact\" | \"compaction_failed\";\n message: string;\n };\n\nexport type PiSessionCommandPayload =\n | { commandId: string; kind: \"prompt\"; input: PiPromptInput }\n | { commandId: string; kind: \"skill\"; input: { name: string; additionalInstructions?: string } }\n | { commandId: string; kind: \"promptFromTemplate\"; input: { name: string; args?: string[] } }\n | { commandId: string; kind: \"compact\"; input: { customInstructions?: string } }\n | { commandId: string; kind: \"abort\"; reason?: string }\n | { commandId: string; kind: \"steer\"; input: PiPromptInput }\n | { commandId: string; kind: \"followUp\"; input: PiPromptInput };\n\nexport type PiAgentStateSnapshot = {\n messages: PiHarnessFrontendAgentMessage[];\n};\n\nexport type PiSessionDetail = PiSession & {\n workflow: {\n status: PiWorkflowStatus;\n error?: { name: string; message: string };\n output?: unknown;\n };\n agent: {\n state: PiAgentStateSnapshot;\n };\n};\n\nexport type PiToolResultSchema<TDetails> = StandardSchemaV1<unknown, TDetails> | TypeBoxSchema;\n\nexport type PiToolDetailsFromResultSchema<TResultSchema> =\n TResultSchema extends StandardSchemaV1<unknown, infer TDetails>\n ? TDetails\n : TResultSchema extends TypeBoxSchema\n ? Static<TResultSchema>\n : unknown;\n\nexport type PiToolDefinition<\n TParameters extends TypeBoxSchema = TypeBoxSchema,\n TDetails = unknown,\n TResultSchema extends PiToolResultSchema<TDetails> | undefined =\n | PiToolResultSchema<TDetails>\n | undefined,\n> = AgentTool<TParameters, TDetails> & {\n name: string;\n resultSchema?: TResultSchema;\n handoff?: boolean;\n};\n\nexport type AnyPiToolDefinition = Omit<AgentTool<TypeBoxSchema, unknown>, \"execute\"> & {\n name: string;\n resultSchema?: PiToolResultSchema<unknown>;\n handoff?: boolean;\n execute: (\n toolCallId: string,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n params: any,\n signal?: AbortSignal,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n onUpdate?: (partialResult: AgentToolResult<any>) => void,\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n ) => Promise<AgentToolResult<any>>;\n};\n\nexport interface PiFragmentConfig {\n workflows?: WorkflowRegistryEntry[];\n /**\n * Called through a durable hook after a harness operation commits a terminal outcome.\n *\n * Usage reporting currently excludes compact operations and tree navigation with summarization.\n */\n onOperationCompleted?: (\n payload: PiOperationCompletedHookPayload,\n context: HookContext,\n ) => Promise<void> | void;\n /**\n * Optional logging config for internal pi-harness diagnostics.\n */\n logging?: PiLoggerConfig;\n}\n"],"mappings":";;AA+BA,MAAM,gCAAgC,EAAE,OAAO;CAC7C,UAAU,EAAE,OAAO,EAAE,OAAO,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,SAAS;CACrD,aAAa,EAAE,OAAO,EACpB,MAAM,EAAE,OAAO,CAAC,CAAC,SAAS,EAC5B,CAAC;AACH,CAAC;AAED,IAAa,gCAAb,cAAmD,MAAM;CAI5C;CACA;CAJX,OAAgB;CAEhB,YACE,cACA,WACA;EACA,MAAM,YAAY,aAAa,GAAG,UAAU,mCAAmC;EAHtE,KAAA,eAAA;EACA,KAAA,YAAA;EAGT,KAAK,OAAO;CACd;AACF;AAEA,IAAa,8BAAb,cAAiD,MAAM;CAI1C;CACA;CAJX,OAAgB;CAEhB,YACE,cACA,WACA,OACA;EACA,MAAM,iCAAiC,aAAa,GAAG,UAAU,eAAe,EAAE,MAAM,CAAC;EAJhF,KAAA,eAAA;EACA,KAAA,YAAA;EAIT,KAAK,OAAO;CACd;AACF;AAEA,MAAa,wCAAwC,aAM7B;CACtB,MAAM,kBAAkB,SAAS;CACjC,IACE,OAAO,oBAAoB,YAC3B,oBAAoB,QACpB,MAAM,QAAQ,eAAe,KAC7B,CAAC,OAAO,OAAO,iBAAiB,aAAa,GAE7C,OAAO;CAGT,MAAM,SAAS,8BAA8B,UAAU,eAAe;CACtE,IAAI,CAAC,OAAO,SACV,MAAM,IAAI,4BAA4B,SAAS,cAAc,SAAS,IAAI,OAAO,KAAK;CAGxF,OAAO;EACL,IAAI,SAAS;EACb,MAAM,OAAO,KAAK,YAAY;EAC9B,UAAU,OAAO,KAAK,YAAY;EAClC,cAAc,SAAS;EACvB,WAAW,SAAS;EACpB,WAAW,SAAS;CACtB;AACF;;AAoCA,MAAa,mCAAmC,IAAI,OAAO;AAE3D,MAAa,iCAAiC"}
@@ -0,0 +1,46 @@
1
+ import { PI_SESSION_COMMAND_STEP_PREFIX } from "./types.js";
2
+ import { buildStepKey } from "@fragno-dev/workflows/step-identity";
3
+ //#region src/pi/wait-for-command-step.ts
4
+ const COMMAND_STEP_POLL_INTERVAL_MS = 100;
5
+ var CommandStepWaitTimeoutError = class extends Error {
6
+ constructor(workflowName, instanceId, commandId) {
7
+ super(`Timed out waiting for command ${commandId} in ${workflowName}/${instanceId}.`);
8
+ this.name = "CommandStepWaitTimeoutError";
9
+ }
10
+ };
11
+ var CommandStepFailedError = class extends Error {
12
+ constructor(commandId, error) {
13
+ super(`Command ${commandId} failed: ${error.name}: ${error.message}`);
14
+ this.name = "CommandStepFailedError";
15
+ }
16
+ };
17
+ var CommandWorkflowTerminatedError = class extends Error {
18
+ constructor(commandId, status) {
19
+ super(`Command ${commandId} could not complete: workflow is ${status}.`);
20
+ this.name = "CommandWorkflowTerminatedError";
21
+ }
22
+ };
23
+ async function waitForCommandStep(options) {
24
+ const { handlerTx, workflows, workflowName, instanceId, commandId } = options;
25
+ const stepKey = buildStepKey("do", `${PI_SESSION_COMMAND_STEP_PREFIX}${commandId}`);
26
+ const deadline = Date.now() + options.timeoutMs;
27
+ while (true) {
28
+ const outcome = await handlerTx().withServiceCalls(() => [workflows.getStepOutcome(workflowName, instanceId, stepKey)]).transform(({ serviceResult: [result] }) => result).execute();
29
+ switch (outcome.status) {
30
+ case "completed": return;
31
+ case "errored": throw new CommandStepFailedError(commandId, outcome.error);
32
+ case "instance-terminal": throw new CommandWorkflowTerminatedError(commandId, outcome.instanceStatus);
33
+ case "not-started":
34
+ case "waiting": break;
35
+ }
36
+ const remainingMs = deadline - Date.now();
37
+ if (remainingMs <= 0) throw new CommandStepWaitTimeoutError(workflowName, instanceId, commandId);
38
+ await new Promise((resolve) => {
39
+ setTimeout(resolve, Math.min(COMMAND_STEP_POLL_INTERVAL_MS, remainingMs)).unref?.();
40
+ });
41
+ }
42
+ }
43
+ //#endregion
44
+ export { CommandStepFailedError, CommandStepWaitTimeoutError, CommandWorkflowTerminatedError, waitForCommandStep };
45
+
46
+ //# sourceMappingURL=wait-for-command-step.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"wait-for-command-step.js","names":[],"sources":["../../../src/pi/wait-for-command-step.ts"],"sourcesContent":["import { buildStepKey } from \"@fragno-dev/workflows/step-identity\";\n\nimport type { DatabaseHandlerTx } from \"@fragno-dev/db\";\nimport type { WorkflowsFragmentServices } from \"@fragno-dev/workflows\";\n\nimport { PI_SESSION_COMMAND_STEP_PREFIX } from \"./types\";\n\nconst COMMAND_STEP_POLL_INTERVAL_MS = 100;\n\nexport class CommandStepWaitTimeoutError extends Error {\n constructor(workflowName: string, instanceId: string, commandId: string) {\n super(`Timed out waiting for command ${commandId} in ${workflowName}/${instanceId}.`);\n this.name = \"CommandStepWaitTimeoutError\";\n }\n}\n\nexport class CommandStepFailedError extends Error {\n constructor(commandId: string, error: { name: string; message: string }) {\n super(`Command ${commandId} failed: ${error.name}: ${error.message}`);\n this.name = \"CommandStepFailedError\";\n }\n}\n\nexport class CommandWorkflowTerminatedError extends Error {\n constructor(commandId: string, status: string) {\n super(`Command ${commandId} could not complete: workflow is ${status}.`);\n this.name = \"CommandWorkflowTerminatedError\";\n }\n}\n\nexport async function waitForCommandStep(options: {\n handlerTx: DatabaseHandlerTx;\n workflows: WorkflowsFragmentServices;\n workflowName: string;\n instanceId: string;\n commandId: string;\n timeoutMs: number;\n}): Promise<void> {\n const { handlerTx, workflows, workflowName, instanceId, commandId } = options;\n const stepKey = buildStepKey(\"do\", `${PI_SESSION_COMMAND_STEP_PREFIX}${commandId}`);\n const deadline = Date.now() + options.timeoutMs;\n\n while (true) {\n const outcome = await handlerTx()\n .withServiceCalls(\n () => [workflows.getStepOutcome(workflowName, instanceId, stepKey)] as const,\n )\n .transform(({ serviceResult: [result] }) => result)\n .execute();\n\n switch (outcome.status) {\n case \"completed\":\n return;\n case \"errored\":\n throw new CommandStepFailedError(commandId, outcome.error);\n case \"instance-terminal\":\n throw new CommandWorkflowTerminatedError(commandId, outcome.instanceStatus);\n case \"not-started\":\n case \"waiting\":\n break;\n }\n\n const remainingMs = deadline - Date.now();\n if (remainingMs <= 0) {\n throw new CommandStepWaitTimeoutError(workflowName, instanceId, commandId);\n }\n await new Promise<void>((resolve) => {\n const timeout = setTimeout(resolve, Math.min(COMMAND_STEP_POLL_INTERVAL_MS, remainingMs));\n timeout.unref?.();\n });\n }\n}\n"],"mappings":";;;AAOA,MAAM,gCAAgC;AAEtC,IAAa,8BAAb,cAAiD,MAAM;CACrD,YAAY,cAAsB,YAAoB,WAAmB;EACvE,MAAM,iCAAiC,UAAU,MAAM,aAAa,GAAG,WAAW,EAAE;EACpF,KAAK,OAAO;CACd;AACF;AAEA,IAAa,yBAAb,cAA4C,MAAM;CAChD,YAAY,WAAmB,OAA0C;EACvE,MAAM,WAAW,UAAU,WAAW,MAAM,KAAK,IAAI,MAAM,SAAS;EACpE,KAAK,OAAO;CACd;AACF;AAEA,IAAa,iCAAb,cAAoD,MAAM;CACxD,YAAY,WAAmB,QAAgB;EAC7C,MAAM,WAAW,UAAU,mCAAmC,OAAO,EAAE;EACvE,KAAK,OAAO;CACd;AACF;AAEA,eAAsB,mBAAmB,SAOvB;CAChB,MAAM,EAAE,WAAW,WAAW,cAAc,YAAY,cAAc;CACtE,MAAM,UAAU,aAAa,MAAM,GAAG,iCAAiC,WAAW;CAClF,MAAM,WAAW,KAAK,IAAI,IAAI,QAAQ;CAEtC,OAAO,MAAM;EACX,MAAM,UAAU,MAAM,UAAU,CAAC,CAC9B,uBACO,CAAC,UAAU,eAAe,cAAc,YAAY,OAAO,CAAC,CACpE,CAAC,CACA,WAAW,EAAE,eAAe,CAAC,cAAc,MAAM,CAAC,CAClD,QAAQ;EAEX,QAAQ,QAAQ,QAAhB;GACE,KAAK,aACH;GACF,KAAK,WACH,MAAM,IAAI,uBAAuB,WAAW,QAAQ,KAAK;GAC3D,KAAK,qBACH,MAAM,IAAI,+BAA+B,WAAW,QAAQ,cAAc;GAC5E,KAAK;GACL,KAAK,WACH;EACJ;EAEA,MAAM,cAAc,WAAW,KAAK,IAAI;EACxC,IAAI,eAAe,GACjB,MAAM,IAAI,4BAA4B,cAAc,YAAY,SAAS;EAE3E,MAAM,IAAI,SAAe,YAAY;GAEnC,WAD2B,SAAS,KAAK,IAAI,+BAA+B,WAAW,CACjF,CAAC,CAAC,QAAQ;EAClB,CAAC;CACH;AACF"}