@endora-commerce/mod-prompt-actions 0.0.0-stage → 0.100.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.
- package/LICENSE +21 -0
- package/README.md +51 -2
- package/dist/backend/entities/prompt-action-request.entity.d.ts +37 -0
- package/dist/backend/entities/prompt-action-request.entity.d.ts.map +1 -0
- package/dist/backend/entities/prompt-action-request.entity.js +130 -0
- package/dist/backend/entities/prompt-action-request.entity.js.map +1 -0
- package/dist/backend/index.d.ts +94 -0
- package/dist/backend/index.d.ts.map +1 -0
- package/dist/backend/index.js +127 -0
- package/dist/backend/index.js.map +1 -0
- package/dist/backend/routes.admin.d.ts +30 -0
- package/dist/backend/routes.admin.d.ts.map +1 -0
- package/dist/backend/routes.admin.js +71 -0
- package/dist/backend/routes.admin.js.map +1 -0
- package/dist/backend/services/bulk-progress-registry.d.ts +82 -0
- package/dist/backend/services/bulk-progress-registry.d.ts.map +1 -0
- package/dist/backend/services/bulk-progress-registry.js +44 -0
- package/dist/backend/services/bulk-progress-registry.js.map +1 -0
- package/dist/backend/services/interpreter.service.d.ts +59 -0
- package/dist/backend/services/interpreter.service.d.ts.map +1 -0
- package/dist/backend/services/interpreter.service.js +270 -0
- package/dist/backend/services/interpreter.service.js.map +1 -0
- package/dist/backend/services/llm/anthropic-adapter.d.ts +9 -0
- package/dist/backend/services/llm/anthropic-adapter.d.ts.map +1 -0
- package/dist/backend/services/llm/anthropic-adapter.js +83 -0
- package/dist/backend/services/llm/anthropic-adapter.js.map +1 -0
- package/dist/backend/services/llm/google-adapter.d.ts +9 -0
- package/dist/backend/services/llm/google-adapter.d.ts.map +1 -0
- package/dist/backend/services/llm/google-adapter.js +125 -0
- package/dist/backend/services/llm/google-adapter.js.map +1 -0
- package/dist/backend/services/llm/openai-adapter.d.ts +9 -0
- package/dist/backend/services/llm/openai-adapter.d.ts.map +1 -0
- package/dist/backend/services/llm/openai-adapter.js +95 -0
- package/dist/backend/services/llm/openai-adapter.js.map +1 -0
- package/dist/backend/services/llm/provider-factory.d.ts +60 -0
- package/dist/backend/services/llm/provider-factory.d.ts.map +1 -0
- package/dist/backend/services/llm/provider-factory.js +111 -0
- package/dist/backend/services/llm/provider-factory.js.map +1 -0
- package/dist/backend/services/llm/provider.d.ts +63 -0
- package/dist/backend/services/llm/provider.d.ts.map +1 -0
- package/dist/backend/services/llm/provider.js +67 -0
- package/dist/backend/services/llm/provider.js.map +1 -0
- package/dist/backend/services/plan-executor.service.d.ts +49 -0
- package/dist/backend/services/plan-executor.service.d.ts.map +1 -0
- package/dist/backend/services/plan-executor.service.js +132 -0
- package/dist/backend/services/plan-executor.service.js.map +1 -0
- package/dist/backend/services/prompt-request.service.d.ts +84 -0
- package/dist/backend/services/prompt-request.service.d.ts.map +1 -0
- package/dist/backend/services/prompt-request.service.js +338 -0
- package/dist/backend/services/prompt-request.service.js.map +1 -0
- package/dist/backend/services/tool-registry.d.ts +17 -0
- package/dist/backend/services/tool-registry.d.ts.map +1 -0
- package/dist/backend/services/tool-registry.js +89 -0
- package/dist/backend/services/tool-registry.js.map +1 -0
- package/dist/manifest.d.ts +252 -0
- package/dist/manifest.d.ts.map +1 -0
- package/dist/manifest.js +199 -0
- package/dist/manifest.js.map +1 -0
- package/dist/migrations/20260611T140410_prompt_actions_init.d.ts +17 -0
- package/dist/migrations/20260611T140410_prompt_actions_init.d.ts.map +1 -0
- package/dist/migrations/20260611T140410_prompt_actions_init.js +47 -0
- package/dist/migrations/20260611T140410_prompt_actions_init.js.map +1 -0
- package/dist/migrations/index.d.ts +27 -0
- package/dist/migrations/index.d.ts.map +1 -0
- package/dist/migrations/index.js +29 -0
- package/dist/migrations/index.js.map +1 -0
- package/docs/prompt-actions.md +117 -0
- package/i18n/en.json +40 -0
- package/i18n/pl.json +40 -0
- package/package.json +67 -3
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { fromWireName, parseOrThrow, postJson, toWireName, wireNameMap, } from './provider.js';
|
|
3
|
+
/**
|
|
4
|
+
* Google (Gemini) adapter — `POST :generateContent` with
|
|
5
|
+
* functionDeclarations / functionCall parts. Native fetch, no SDK
|
|
6
|
+
* (research §R2). Gemini returns no tool-call ids, so synthetic ids are
|
|
7
|
+
* minted per response; functionResponse parts are matched by name, which the
|
|
8
|
+
* API expects.
|
|
9
|
+
*/
|
|
10
|
+
const ResponseSchema = z.object({
|
|
11
|
+
candidates: z
|
|
12
|
+
.array(z.object({
|
|
13
|
+
content: z.object({
|
|
14
|
+
parts: z
|
|
15
|
+
.array(z.union([
|
|
16
|
+
z.object({ text: z.string() }),
|
|
17
|
+
z.object({
|
|
18
|
+
functionCall: z.object({ name: z.string(), args: z.unknown().optional() }),
|
|
19
|
+
}),
|
|
20
|
+
]))
|
|
21
|
+
.default([]),
|
|
22
|
+
}),
|
|
23
|
+
finishReason: z.string().optional(),
|
|
24
|
+
}))
|
|
25
|
+
.min(1),
|
|
26
|
+
});
|
|
27
|
+
/** Gemini's parameter schema is an OpenAPI subset — strip JSON-Schema-only keys. */
|
|
28
|
+
function sanitizeForGemini(schema) {
|
|
29
|
+
if (Array.isArray(schema))
|
|
30
|
+
return schema.map(sanitizeForGemini);
|
|
31
|
+
if (typeof schema !== 'object' || schema === null)
|
|
32
|
+
return schema;
|
|
33
|
+
const out = {};
|
|
34
|
+
for (const [k, v] of Object.entries(schema)) {
|
|
35
|
+
if (k === '$schema' || k === 'additionalProperties')
|
|
36
|
+
continue;
|
|
37
|
+
out[k] = sanitizeForGemini(v);
|
|
38
|
+
}
|
|
39
|
+
return out;
|
|
40
|
+
}
|
|
41
|
+
export class GoogleAdapter {
|
|
42
|
+
apiKey;
|
|
43
|
+
fetchImpl;
|
|
44
|
+
provider = 'google';
|
|
45
|
+
constructor(apiKey, fetchImpl = fetch) {
|
|
46
|
+
this.apiKey = apiKey;
|
|
47
|
+
this.fetchImpl = fetchImpl;
|
|
48
|
+
}
|
|
49
|
+
async complete(req) {
|
|
50
|
+
const names = wireNameMap(req.tools);
|
|
51
|
+
const body = {
|
|
52
|
+
systemInstruction: { parts: [{ text: req.system }] },
|
|
53
|
+
generationConfig: { maxOutputTokens: req.maxTokens },
|
|
54
|
+
tools: [
|
|
55
|
+
{
|
|
56
|
+
functionDeclarations: req.tools.map((t) => ({
|
|
57
|
+
name: toWireName(t.name),
|
|
58
|
+
description: t.description,
|
|
59
|
+
parameters: sanitizeForGemini(t.inputSchema),
|
|
60
|
+
})),
|
|
61
|
+
},
|
|
62
|
+
],
|
|
63
|
+
contents: req.messages.map((m) => {
|
|
64
|
+
if (m.role === 'user')
|
|
65
|
+
return { role: 'user', parts: [{ text: m.text }] };
|
|
66
|
+
if (m.role === 'assistant') {
|
|
67
|
+
return {
|
|
68
|
+
role: 'model',
|
|
69
|
+
parts: [
|
|
70
|
+
...(m.text ? [{ text: m.text }] : []),
|
|
71
|
+
...m.toolCalls.map((c) => ({
|
|
72
|
+
functionCall: { name: toWireName(c.name), args: c.arguments ?? {} },
|
|
73
|
+
})),
|
|
74
|
+
],
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
let response;
|
|
78
|
+
try {
|
|
79
|
+
response = JSON.parse(m.resultJson);
|
|
80
|
+
}
|
|
81
|
+
catch {
|
|
82
|
+
response = { value: m.resultJson };
|
|
83
|
+
}
|
|
84
|
+
// functionResponse.response must be an object.
|
|
85
|
+
const wrapped = typeof response === 'object' && response !== null && !Array.isArray(response)
|
|
86
|
+
? response
|
|
87
|
+
: { value: response };
|
|
88
|
+
return {
|
|
89
|
+
role: 'user',
|
|
90
|
+
parts: [
|
|
91
|
+
{ functionResponse: { name: toWireName(m.toolName), response: wrapped } },
|
|
92
|
+
],
|
|
93
|
+
};
|
|
94
|
+
}),
|
|
95
|
+
};
|
|
96
|
+
const json = await postJson(this.provider, this.fetchImpl, `https://generativelanguage.googleapis.com/v1beta/models/${encodeURIComponent(req.model)}:generateContent`, { 'x-goog-api-key': this.apiKey }, body);
|
|
97
|
+
const parsed = parseOrThrow(this.provider, ResponseSchema, json);
|
|
98
|
+
const candidate = parsed.candidates[0];
|
|
99
|
+
const texts = [];
|
|
100
|
+
const toolCalls = [];
|
|
101
|
+
candidate.content.parts.forEach((part, index) => {
|
|
102
|
+
if ('text' in part) {
|
|
103
|
+
texts.push(part.text);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
toolCalls.push({
|
|
107
|
+
id: `gcall_${index}_${part.functionCall.name}`,
|
|
108
|
+
name: fromWireName(part.functionCall.name, names),
|
|
109
|
+
arguments: part.functionCall.args ?? {},
|
|
110
|
+
});
|
|
111
|
+
});
|
|
112
|
+
return {
|
|
113
|
+
text: texts.length > 0 ? texts.join('\n') : null,
|
|
114
|
+
toolCalls,
|
|
115
|
+
stopReason: toolCalls.length > 0
|
|
116
|
+
? 'tool_use'
|
|
117
|
+
: candidate.finishReason === 'STOP'
|
|
118
|
+
? 'end'
|
|
119
|
+
: candidate.finishReason === 'MAX_TOKENS'
|
|
120
|
+
? 'max_tokens'
|
|
121
|
+
: 'other',
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
//# sourceMappingURL=google-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"google-adapter.js","sourceRoot":"","sources":["../../../../src/backend/services/llm/google-adapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AACxB,OAAO,EACL,YAAY,EACZ,YAAY,EACZ,QAAQ,EACR,UAAU,EACV,WAAW,GAKZ,MAAM,eAAe,CAAC;AAEvB;;;;;;GAMG;AAEH,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IAC9B,UAAU,EAAE,CAAC;SACV,KAAK,CACJ,CAAC,CAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC,CAAC,MAAM,CAAC;YAChB,KAAK,EAAE,CAAC;iBACL,KAAK,CACJ,CAAC,CAAC,KAAK,CAAC;gBACN,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC;gBAC9B,CAAC,CAAC,MAAM,CAAC;oBACP,YAAY,EAAE,CAAC,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,IAAI,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC;iBAC3E,CAAC;aACH,CAAC,CACH;iBACA,OAAO,CAAC,EAAE,CAAC;SACf,CAAC;QACF,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;KACpC,CAAC,CACH;SACA,GAAG,CAAC,CAAC,CAAC;CACV,CAAC,CAAC;AAEH,oFAAoF;AACpF,SAAS,iBAAiB,CAAC,MAAe;IACxC,IAAI,KAAK,CAAC,OAAO,CAAC,MAAM,CAAC;QAAE,OAAO,MAAM,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC;IAChE,IAAI,OAAO,MAAM,KAAK,QAAQ,IAAI,MAAM,KAAK,IAAI;QAAE,OAAO,MAAM,CAAC;IACjE,MAAM,GAAG,GAA4B,EAAE,CAAC;IACxC,KAAK,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAiC,CAAC,EAAE,CAAC;QACvE,IAAI,CAAC,KAAK,SAAS,IAAI,CAAC,KAAK,sBAAsB;YAAE,SAAS;QAC9D,GAAG,CAAC,CAAC,CAAC,GAAG,iBAAiB,CAAC,CAAC,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,MAAM,OAAO,aAAa;IAIL;IACA;IAJV,QAAQ,GAAG,QAAiB,CAAC;IAEtC,YACmB,MAAc,EACd,YAAuB,KAAK;QAD5B,WAAM,GAAN,MAAM,CAAQ;QACd,cAAS,GAAT,SAAS,CAAmB;IAC5C,CAAC;IAEJ,KAAK,CAAC,QAAQ,CAAC,GAAe;QAC5B,MAAM,KAAK,GAAG,WAAW,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;QACrC,MAAM,IAAI,GAAG;YACX,iBAAiB,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,GAAG,CAAC,MAAM,EAAE,CAAC,EAAE;YACpD,gBAAgB,EAAE,EAAE,eAAe,EAAE,GAAG,CAAC,SAAS,EAAE;YACpD,KAAK,EAAE;gBACL;oBACE,oBAAoB,EAAE,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;wBAC1C,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC;wBACxB,WAAW,EAAE,CAAC,CAAC,WAAW;wBAC1B,UAAU,EAAE,iBAAiB,CAAC,CAAC,CAAC,WAAW,CAAC;qBAC7C,CAAC,CAAC;iBACJ;aACF;YACD,QAAQ,EAAE,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBAC/B,IAAI,CAAC,CAAC,IAAI,KAAK,MAAM;oBAAE,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;gBAC1E,IAAI,CAAC,CAAC,IAAI,KAAK,WAAW,EAAE,CAAC;oBAC3B,OAAO;wBACL,IAAI,EAAE,OAAO;wBACb,KAAK,EAAE;4BACL,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;4BACrC,GAAG,CAAC,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gCACzB,YAAY,EAAE,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,SAAS,IAAI,EAAE,EAAE;6BACpE,CAAC,CAAC;yBACJ;qBACF,CAAC;gBACJ,CAAC;gBACD,IAAI,QAAiB,CAAC;gBACtB,IAAI,CAAC;oBACH,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC;gBACtC,CAAC;gBAAC,MAAM,CAAC;oBACP,QAAQ,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC,UAAU,EAAE,CAAC;gBACrC,CAAC;gBACD,+CAA+C;gBAC/C,MAAM,OAAO,GACX,OAAO,QAAQ,KAAK,QAAQ,IAAI,QAAQ,KAAK,IAAI,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;oBAC3E,CAAC,CAAC,QAAQ;oBACV,CAAC,CAAC,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC;gBAC1B,OAAO;oBACL,IAAI,EAAE,MAAM;oBACZ,KAAK,EAAE;wBACL,EAAE,gBAAgB,EAAE,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,QAAQ,EAAE,OAAO,EAAE,EAAE;qBAC1E;iBACF,CAAC;YACJ,CAAC,CAAC;SACH,CAAC;QAEF,MAAM,IAAI,GAAG,MAAM,QAAQ,CACzB,IAAI,CAAC,QAAQ,EACb,IAAI,CAAC,SAAS,EACd,2DAA2D,kBAAkB,CAAC,GAAG,CAAC,KAAK,CAAC,kBAAkB,EAC1G,EAAE,gBAAgB,EAAE,IAAI,CAAC,MAAM,EAAE,EACjC,IAAI,CACL,CAAC;QACF,MAAM,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,cAAc,EAAE,IAAI,CAAC,CAAC;QACjE,MAAM,SAAS,GAAG,MAAM,CAAC,UAAU,CAAC,CAAC,CAAE,CAAC;QAExC,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,MAAM,SAAS,GAA+B,EAAE,CAAC;QACjD,SAAS,CAAC,OAAO,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;YAC9C,IAAI,MAAM,IAAI,IAAI,EAAE,CAAC;gBACnB,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;gBACtB,OAAO;YACT,CAAC;YACD,SAAS,CAAC,IAAI,CAAC;gBACb,EAAE,EAAE,SAAS,KAAK,IAAI,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE;gBAC9C,IAAI,EAAE,YAAY,CAAC,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,KAAK,CAAC;gBACjD,SAAS,EAAE,IAAI,CAAC,YAAY,CAAC,IAAI,IAAI,EAAE;aACxC,CAAC,CAAC;QACL,CAAC,CAAC,CAAC;QAEH,OAAO;YACL,IAAI,EAAE,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI;YAChD,SAAS;YACT,UAAU,EACR,SAAS,CAAC,MAAM,GAAG,CAAC;gBAClB,CAAC,CAAC,UAAU;gBACZ,CAAC,CAAC,SAAS,CAAC,YAAY,KAAK,MAAM;oBACjC,CAAC,CAAC,KAAK;oBACP,CAAC,CAAC,SAAS,CAAC,YAAY,KAAK,YAAY;wBACvC,CAAC,CAAC,YAAY;wBACd,CAAC,CAAC,OAAO;SAClB,CAAC;IACJ,CAAC;CACF"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { type FetchLike, type LlmCompletion, type LlmProviderAdapter, type LlmRequest } from './provider.js';
|
|
2
|
+
export declare class OpenAiAdapter implements LlmProviderAdapter {
|
|
3
|
+
private readonly apiKey;
|
|
4
|
+
private readonly fetchImpl;
|
|
5
|
+
readonly provider: "openai";
|
|
6
|
+
constructor(apiKey: string, fetchImpl?: FetchLike);
|
|
7
|
+
complete(req: LlmRequest): Promise<LlmCompletion>;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=openai-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-adapter.d.ts","sourceRoot":"","sources":["../../../../src/backend/services/llm/openai-adapter.ts"],"names":[],"mappings":"AACA,OAAO,EAOL,KAAK,SAAS,EACd,KAAK,aAAa,EAClB,KAAK,kBAAkB,EACvB,KAAK,UAAU,EAChB,MAAM,eAAe,CAAC;AA8BvB,qBAAa,aAAc,YAAW,kBAAkB;IAIpD,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,SAAS;IAJ5B,QAAQ,CAAC,QAAQ,EAAG,QAAQ,CAAU;gBAGnB,MAAM,EAAE,MAAM,EACd,SAAS,GAAE,SAAiB;IAGzC,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC;CAyExD"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { LlmProviderError, fromWireName, parseOrThrow, postJson, toWireName, wireNameMap, } from './provider.js';
|
|
3
|
+
/**
|
|
4
|
+
* OpenAI (GPT) adapter — `POST /v1/chat/completions` with tools/tool_calls.
|
|
5
|
+
* Native fetch, no SDK (research §R2). Tool-call arguments arrive as a JSON
|
|
6
|
+
* string and are parsed here; the interpreter re-validates against the
|
|
7
|
+
* tool's Zod schema regardless.
|
|
8
|
+
*/
|
|
9
|
+
const ResponseSchema = z.object({
|
|
10
|
+
choices: z
|
|
11
|
+
.array(z.object({
|
|
12
|
+
message: z.object({
|
|
13
|
+
content: z.string().nullable().optional(),
|
|
14
|
+
tool_calls: z
|
|
15
|
+
.array(z.object({
|
|
16
|
+
id: z.string(),
|
|
17
|
+
function: z.object({ name: z.string(), arguments: z.string() }),
|
|
18
|
+
}))
|
|
19
|
+
.optional(),
|
|
20
|
+
}),
|
|
21
|
+
finish_reason: z.string().nullable().optional(),
|
|
22
|
+
}))
|
|
23
|
+
.min(1),
|
|
24
|
+
});
|
|
25
|
+
export class OpenAiAdapter {
|
|
26
|
+
apiKey;
|
|
27
|
+
fetchImpl;
|
|
28
|
+
provider = 'openai';
|
|
29
|
+
constructor(apiKey, fetchImpl = fetch) {
|
|
30
|
+
this.apiKey = apiKey;
|
|
31
|
+
this.fetchImpl = fetchImpl;
|
|
32
|
+
}
|
|
33
|
+
async complete(req) {
|
|
34
|
+
const names = wireNameMap(req.tools);
|
|
35
|
+
const body = {
|
|
36
|
+
model: req.model,
|
|
37
|
+
max_completion_tokens: req.maxTokens,
|
|
38
|
+
messages: [
|
|
39
|
+
{ role: 'system', content: req.system },
|
|
40
|
+
...req.messages.map((m) => {
|
|
41
|
+
if (m.role === 'user')
|
|
42
|
+
return { role: 'user', content: m.text };
|
|
43
|
+
if (m.role === 'assistant') {
|
|
44
|
+
return {
|
|
45
|
+
role: 'assistant',
|
|
46
|
+
content: m.text,
|
|
47
|
+
...(m.toolCalls.length > 0
|
|
48
|
+
? {
|
|
49
|
+
tool_calls: m.toolCalls.map((c) => ({
|
|
50
|
+
id: c.id,
|
|
51
|
+
type: 'function',
|
|
52
|
+
function: {
|
|
53
|
+
name: toWireName(c.name),
|
|
54
|
+
arguments: JSON.stringify(c.arguments),
|
|
55
|
+
},
|
|
56
|
+
})),
|
|
57
|
+
}
|
|
58
|
+
: {}),
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
return { role: 'tool', tool_call_id: m.toolCallId, content: m.resultJson };
|
|
62
|
+
}),
|
|
63
|
+
],
|
|
64
|
+
tools: req.tools.map((t) => ({
|
|
65
|
+
type: 'function',
|
|
66
|
+
function: { name: toWireName(t.name), description: t.description, parameters: t.inputSchema },
|
|
67
|
+
})),
|
|
68
|
+
};
|
|
69
|
+
const json = await postJson(this.provider, this.fetchImpl, 'https://api.openai.com/v1/chat/completions', { authorization: `Bearer ${this.apiKey}` }, body);
|
|
70
|
+
const parsed = parseOrThrow(this.provider, ResponseSchema, json);
|
|
71
|
+
const choice = parsed.choices[0];
|
|
72
|
+
const toolCalls = (choice.message.tool_calls ?? []).map((c) => {
|
|
73
|
+
let args;
|
|
74
|
+
try {
|
|
75
|
+
args = JSON.parse(c.function.arguments);
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
throw new LlmProviderError(this.provider, 'malformed', `openai tool call "${c.function.name}" carried non-JSON arguments.`);
|
|
79
|
+
}
|
|
80
|
+
return { id: c.id, name: fromWireName(c.function.name, names), arguments: args };
|
|
81
|
+
});
|
|
82
|
+
return {
|
|
83
|
+
text: choice.message.content ?? null,
|
|
84
|
+
toolCalls,
|
|
85
|
+
stopReason: choice.finish_reason === 'tool_calls'
|
|
86
|
+
? 'tool_use'
|
|
87
|
+
: choice.finish_reason === 'stop'
|
|
88
|
+
? 'end'
|
|
89
|
+
: choice.finish_reason === 'length'
|
|
90
|
+
? 'max_tokens'
|
|
91
|
+
: 'other',
|
|
92
|
+
};
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=openai-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"openai-adapter.js","sourceRoot":"","sources":["../../../../src/backend/services/llm/openai-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { type PromptActionsCapability, type PromptActionsProvider, type ResolveResult } from '@endora-commerce/contracts';
|
|
3
|
+
import type { FetchLike, LlmProviderAdapter } from './provider.js';
|
|
4
|
+
/**
|
|
5
|
+
* Settings-driven provider factory + capability derivation (feature 043,
|
|
6
|
+
* T023 / US4). Configuration is resolved per call through the Settings
|
|
7
|
+
* universal getter (Redis/LRU-cached), so provider, model and key changes
|
|
8
|
+
* take effect on the next prompt without a restart (US4/AC4). The API key
|
|
9
|
+
* never leaves this module: the capability DTO carries only the status.
|
|
10
|
+
*
|
|
11
|
+
* Feature 058 — the provider/model/key are sourced SOLELY from the
|
|
12
|
+
* `prompt_actions.llm_credentials` reference (a reusable `llm` credential
|
|
13
|
+
* configuration). When that reference is unset or unresolvable, the assistant
|
|
14
|
+
* reports `not_configured` and fails closed; there is no separate provider /
|
|
15
|
+
* model / api_key setting.
|
|
16
|
+
*/
|
|
17
|
+
/** Narrow port over SettingsService so the module depends on a shape, not the class. */
|
|
18
|
+
export interface SettingsReadPort {
|
|
19
|
+
get<T>(code: string, salesChannelId: string, schema: z.ZodType<T>): Promise<T>;
|
|
20
|
+
}
|
|
21
|
+
/** Narrow port over CredentialsService.resolve (feature 058, Principle I). */
|
|
22
|
+
export interface CredentialResolvePort {
|
|
23
|
+
resolve(configurationCode: string): Promise<ResolveResult>;
|
|
24
|
+
}
|
|
25
|
+
export declare class AssistantDisabled extends Error {
|
|
26
|
+
readonly name = "AssistantDisabled";
|
|
27
|
+
readonly code: "ASSISTANT_DISABLED";
|
|
28
|
+
constructor();
|
|
29
|
+
}
|
|
30
|
+
export declare class AssistantNotConfigured extends Error {
|
|
31
|
+
readonly name = "AssistantNotConfigured";
|
|
32
|
+
readonly code: "ASSISTANT_NOT_CONFIGURED";
|
|
33
|
+
constructor();
|
|
34
|
+
}
|
|
35
|
+
export interface LlmProviderFactoryDeps {
|
|
36
|
+
settings: SettingsReadPort;
|
|
37
|
+
/** Channel used to resolve the (global-scope) assistant settings. */
|
|
38
|
+
resolveChannelId: () => Promise<string>;
|
|
39
|
+
fetchImpl?: FetchLike;
|
|
40
|
+
/** Feature 058 — resolves the `prompt_actions.llm_credentials` reference. */
|
|
41
|
+
credentials?: CredentialResolvePort;
|
|
42
|
+
}
|
|
43
|
+
export interface ResolvedAssistant {
|
|
44
|
+
adapter: LlmProviderAdapter;
|
|
45
|
+
provider: PromptActionsProvider;
|
|
46
|
+
model: string;
|
|
47
|
+
bulkLimit: number;
|
|
48
|
+
}
|
|
49
|
+
export declare class LlmProviderFactory {
|
|
50
|
+
private readonly deps;
|
|
51
|
+
constructor(deps: LlmProviderFactoryDeps);
|
|
52
|
+
/** Status surface for the palette — never exposes the key (US4/AC2). */
|
|
53
|
+
capability(): Promise<PromptActionsCapability>;
|
|
54
|
+
/** Adapter for one interpretation run; throws typed errors for the routes. */
|
|
55
|
+
resolve(): Promise<ResolvedAssistant>;
|
|
56
|
+
bulkLimit(): Promise<number>;
|
|
57
|
+
private readConfig;
|
|
58
|
+
private resolveFromCredential;
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=provider-factory.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-factory.d.ts","sourceRoot":"","sources":["../../../../src/backend/services/llm/provider-factory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,OAAO,EAEL,KAAK,uBAAuB,EAC5B,KAAK,qBAAqB,EAC1B,KAAK,aAAa,EACnB,MAAM,4BAA4B,CAAC;AAKpC,OAAO,KAAK,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,eAAe,CAAC;AAEnE;;;;;;;;;;;;GAYG;AAEH,wFAAwF;AACxF,MAAM,WAAW,gBAAgB;IAC/B,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,cAAc,EAAE,MAAM,EAAE,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC,CAAC,CAAC,CAAC;CAChF;AAED,8EAA8E;AAC9E,MAAM,WAAW,qBAAqB;IACpC,OAAO,CAAC,iBAAiB,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CAC5D;AAED,qBAAa,iBAAkB,SAAQ,KAAK;IAC1C,SAAkB,IAAI,uBAAuB;IAC7C,QAAQ,CAAC,IAAI,EAAG,oBAAoB,CAAU;;CAI/C;AAED,qBAAa,sBAAuB,SAAQ,KAAK;IAC/C,SAAkB,IAAI,4BAA4B;IAClD,QAAQ,CAAC,IAAI,EAAG,0BAA0B,CAAU;;CAIrD;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,EAAE,gBAAgB,CAAC;IAC3B,qEAAqE;IACrE,gBAAgB,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,CAAC;IACxC,SAAS,CAAC,EAAE,SAAS,CAAC;IACtB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,qBAAqB,CAAC;CACrC;AAED,MAAM,WAAW,iBAAiB;IAChC,OAAO,EAAE,kBAAkB,CAAC;IAC5B,QAAQ,EAAE,qBAAqB,CAAC;IAChC,KAAK,EAAE,MAAM,CAAC;IACd,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,qBAAa,kBAAkB;IACjB,OAAO,CAAC,QAAQ,CAAC,IAAI;gBAAJ,IAAI,EAAE,sBAAsB;IAEzD,wEAAwE;IAClE,UAAU,IAAI,OAAO,CAAC,uBAAuB,CAAC;IASpD,8EAA8E;IACxE,OAAO,IAAI,OAAO,CAAC,iBAAiB,CAAC;IAcrC,SAAS,IAAI,OAAO,CAAC,MAAM,CAAC;YAIpB,UAAU;YAqCV,qBAAqB;CAuBpC"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { rethrowIfModuleDisabled } from '@endora-commerce/platform/kernel';
|
|
3
|
+
import { PromptActionsProviderSchema, } from '@endora-commerce/contracts';
|
|
4
|
+
import { PROMPT_ACTIONS_SETTING_CODES } from '../../../manifest.js';
|
|
5
|
+
import { AnthropicAdapter } from './anthropic-adapter.js';
|
|
6
|
+
import { GoogleAdapter } from './google-adapter.js';
|
|
7
|
+
import { OpenAiAdapter } from './openai-adapter.js';
|
|
8
|
+
export class AssistantDisabled extends Error {
|
|
9
|
+
name = 'AssistantDisabled';
|
|
10
|
+
code = 'ASSISTANT_DISABLED';
|
|
11
|
+
constructor() {
|
|
12
|
+
super('The prompt assistant is disabled on this platform.');
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
export class AssistantNotConfigured extends Error {
|
|
16
|
+
name = 'AssistantNotConfigured';
|
|
17
|
+
code = 'ASSISTANT_NOT_CONFIGURED';
|
|
18
|
+
constructor() {
|
|
19
|
+
super('The prompt assistant is enabled but its provider settings are incomplete.');
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
export class LlmProviderFactory {
|
|
23
|
+
deps;
|
|
24
|
+
constructor(deps) {
|
|
25
|
+
this.deps = deps;
|
|
26
|
+
}
|
|
27
|
+
/** Status surface for the palette — never exposes the key (US4/AC2). */
|
|
28
|
+
async capability() {
|
|
29
|
+
const cfg = await this.readConfig();
|
|
30
|
+
if (!cfg.enabled)
|
|
31
|
+
return { status: 'disabled', bulkLimit: cfg.bulkLimit };
|
|
32
|
+
if (!cfg.provider || !cfg.model || !cfg.apiKey) {
|
|
33
|
+
return { status: 'not_configured', bulkLimit: cfg.bulkLimit };
|
|
34
|
+
}
|
|
35
|
+
return { status: 'ready', bulkLimit: cfg.bulkLimit };
|
|
36
|
+
}
|
|
37
|
+
/** Adapter for one interpretation run; throws typed errors for the routes. */
|
|
38
|
+
async resolve() {
|
|
39
|
+
const cfg = await this.readConfig();
|
|
40
|
+
if (!cfg.enabled)
|
|
41
|
+
throw new AssistantDisabled();
|
|
42
|
+
if (!cfg.provider || !cfg.model || !cfg.apiKey)
|
|
43
|
+
throw new AssistantNotConfigured();
|
|
44
|
+
const fetchImpl = this.deps.fetchImpl ?? fetch;
|
|
45
|
+
const adapter = cfg.provider === 'anthropic'
|
|
46
|
+
? new AnthropicAdapter(cfg.apiKey, fetchImpl)
|
|
47
|
+
: cfg.provider === 'google'
|
|
48
|
+
? new GoogleAdapter(cfg.apiKey, fetchImpl)
|
|
49
|
+
: new OpenAiAdapter(cfg.apiKey, fetchImpl);
|
|
50
|
+
return { adapter, provider: cfg.provider, model: cfg.model, bulkLimit: cfg.bulkLimit };
|
|
51
|
+
}
|
|
52
|
+
async bulkLimit() {
|
|
53
|
+
return (await this.readConfig()).bulkLimit;
|
|
54
|
+
}
|
|
55
|
+
async readConfig() {
|
|
56
|
+
const channelId = await this.deps.resolveChannelId();
|
|
57
|
+
const read = async (code, schema, fallback) => {
|
|
58
|
+
try {
|
|
59
|
+
return await this.deps.settings.get(code, channelId, schema);
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// Not seeded yet / out of scope — treat as unset rather than erroring
|
|
63
|
+
// the palette (mirrors the resolveModerationMode degrade pattern).
|
|
64
|
+
return fallback;
|
|
65
|
+
}
|
|
66
|
+
};
|
|
67
|
+
const [enabled, refCode, bulkLimit] = await Promise.all([
|
|
68
|
+
read(PROMPT_ACTIONS_SETTING_CODES.ENABLED, z.boolean(), false),
|
|
69
|
+
read(PROMPT_ACTIONS_SETTING_CODES.LLM_CREDENTIALS, z.string(), ''),
|
|
70
|
+
read(PROMPT_ACTIONS_SETTING_CODES.BULK_LIMIT, z.number().int().positive(), 500),
|
|
71
|
+
]);
|
|
72
|
+
// Feature 058 — the `prompt_actions.llm_credentials` reference is the SINGLE
|
|
73
|
+
// source of provider/model/apiKey. When it is unset or unresolvable (or
|
|
74
|
+
// resolves to a provider prompt_actions has no adapter for), the assistant
|
|
75
|
+
// reports `not_configured` and fails closed — there is no legacy path.
|
|
76
|
+
const fromCredential = await this.resolveFromCredential(refCode.trim());
|
|
77
|
+
return {
|
|
78
|
+
enabled,
|
|
79
|
+
provider: fromCredential?.provider ?? null,
|
|
80
|
+
model: fromCredential?.model ?? '',
|
|
81
|
+
apiKey: fromCredential?.apiKey ?? '',
|
|
82
|
+
bulkLimit,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
async resolveFromCredential(refCode) {
|
|
86
|
+
if (!this.deps.credentials || !refCode)
|
|
87
|
+
return null;
|
|
88
|
+
// Tolerated: an unresolvable reference means the assistant is not
|
|
89
|
+
// configured, and reporting that is the product's answer (feature 058).
|
|
90
|
+
// **A presence answer is a different sentence**: with `credentials` off
|
|
91
|
+
// there is nothing for the operator to configure, and `not_configured`
|
|
92
|
+
// would send them to fix a setting that is already right.
|
|
93
|
+
const resolved = await this.deps.credentials.resolve(refCode).catch((error) => {
|
|
94
|
+
rethrowIfModuleDisabled(error);
|
|
95
|
+
return null;
|
|
96
|
+
});
|
|
97
|
+
if (!resolved || resolved.status !== 'ok')
|
|
98
|
+
return null;
|
|
99
|
+
// Only providers prompt_actions has an adapter for (anthropic/google/openai)
|
|
100
|
+
// are usable; any other resolved provider (e.g. deepseek) is not_configured.
|
|
101
|
+
const provider = PromptActionsProviderSchema.safeParse(resolved.providerCode);
|
|
102
|
+
if (!provider.success)
|
|
103
|
+
return null;
|
|
104
|
+
const model = typeof resolved.values['model'] === 'string' ? resolved.values['model'].trim() : '';
|
|
105
|
+
const apiKey = typeof resolved.values['apiKey'] === 'string' ? resolved.values['apiKey'].trim() : '';
|
|
106
|
+
if (!model || !apiKey)
|
|
107
|
+
return null;
|
|
108
|
+
return { provider: provider.data, model, apiKey };
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=provider-factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-factory.js","sourceRoot":"","sources":["../../../../src/backend/services/llm/provider-factory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import type { z } from 'zod';
|
|
2
|
+
import type { LlmToolDefinition, PromptActionsProvider } from '@endora-commerce/contracts';
|
|
3
|
+
/**
|
|
4
|
+
* Provider-neutral LLM adapter contract (feature 043, research §R2).
|
|
5
|
+
*
|
|
6
|
+
* Three thin adapters (Anthropic / Google / OpenAI) speak the providers'
|
|
7
|
+
* native tool-calling REST APIs over injected `fetch` — no SDK dependency.
|
|
8
|
+
* Everything the interpreter consumes is normalized to this shape; provider
|
|
9
|
+
* responses are Zod-validated at the boundary (Principle V).
|
|
10
|
+
*/
|
|
11
|
+
export type { LlmToolDefinition };
|
|
12
|
+
export type LlmMessage = {
|
|
13
|
+
role: 'user';
|
|
14
|
+
text: string;
|
|
15
|
+
} | {
|
|
16
|
+
role: 'assistant';
|
|
17
|
+
text: string | null;
|
|
18
|
+
toolCalls: LlmToolCall[];
|
|
19
|
+
} | {
|
|
20
|
+
role: 'tool_result';
|
|
21
|
+
toolCallId: string;
|
|
22
|
+
toolName: string;
|
|
23
|
+
resultJson: string;
|
|
24
|
+
};
|
|
25
|
+
export interface LlmToolCall {
|
|
26
|
+
id: string;
|
|
27
|
+
/** Dotted registry id, e.g. 'inventory.set_stock_level'. */
|
|
28
|
+
name: string;
|
|
29
|
+
arguments: unknown;
|
|
30
|
+
}
|
|
31
|
+
export interface LlmRequest {
|
|
32
|
+
model: string;
|
|
33
|
+
system: string;
|
|
34
|
+
messages: LlmMessage[];
|
|
35
|
+
tools: LlmToolDefinition[];
|
|
36
|
+
maxTokens: number;
|
|
37
|
+
}
|
|
38
|
+
export interface LlmCompletion {
|
|
39
|
+
text: string | null;
|
|
40
|
+
toolCalls: LlmToolCall[];
|
|
41
|
+
stopReason: 'tool_use' | 'end' | 'max_tokens' | 'other';
|
|
42
|
+
}
|
|
43
|
+
export interface LlmProviderAdapter {
|
|
44
|
+
readonly provider: PromptActionsProvider;
|
|
45
|
+
complete(req: LlmRequest): Promise<LlmCompletion>;
|
|
46
|
+
}
|
|
47
|
+
export declare class LlmProviderError extends Error {
|
|
48
|
+
readonly provider: PromptActionsProvider;
|
|
49
|
+
readonly kind: 'http' | 'network' | 'malformed';
|
|
50
|
+
readonly status?: number | undefined;
|
|
51
|
+
readonly name = "LlmProviderError";
|
|
52
|
+
constructor(provider: PromptActionsProvider, kind: 'http' | 'network' | 'malformed', message: string, status?: number | undefined);
|
|
53
|
+
}
|
|
54
|
+
export type FetchLike = typeof fetch;
|
|
55
|
+
export declare function toWireName(id: string): string;
|
|
56
|
+
export declare function wireNameMap(tools: LlmToolDefinition[]): Map<string, string>;
|
|
57
|
+
export declare function fromWireName(wire: string, map: Map<string, string>): string;
|
|
58
|
+
/** Shared POST + JSON helper with uniform error mapping. */
|
|
59
|
+
export declare function postJson(provider: PromptActionsProvider, fetchImpl: FetchLike, url: string, headers: Record<string, string>, body: unknown): Promise<unknown>;
|
|
60
|
+
export declare function malformed(provider: PromptActionsProvider, issues: unknown): LlmProviderError;
|
|
61
|
+
/** Boundary guard reused by adapters. */
|
|
62
|
+
export declare function parseOrThrow<T>(provider: PromptActionsProvider, schema: z.ZodType<T>, value: unknown): T;
|
|
63
|
+
//# sourceMappingURL=provider.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../../../src/backend/services/llm/provider.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAC7B,OAAO,KAAK,EAAE,iBAAiB,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAE3F;;;;;;;GAOG;AAEH,YAAY,EAAE,iBAAiB,EAAE,CAAC;AAElC,MAAM,MAAM,UAAU,GAClB;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,WAAW,CAAC;IAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IAAC,SAAS,EAAE,WAAW,EAAE,CAAA;CAAE,GACpE;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,UAAU,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAC;IAAC,UAAU,EAAE,MAAM,CAAA;CAAE,CAAC;AAEtF,MAAM,WAAW,WAAW;IAC1B,EAAE,EAAE,MAAM,CAAC;IACX,4DAA4D;IAC5D,IAAI,EAAE,MAAM,CAAC;IACb,SAAS,EAAE,OAAO,CAAC;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;IACf,QAAQ,EAAE,UAAU,EAAE,CAAC;IACvB,KAAK,EAAE,iBAAiB,EAAE,CAAC;IAC3B,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,aAAa;IAC5B,IAAI,EAAE,MAAM,GAAG,IAAI,CAAC;IACpB,SAAS,EAAE,WAAW,EAAE,CAAC;IACzB,UAAU,EAAE,UAAU,GAAG,KAAK,GAAG,YAAY,GAAG,OAAO,CAAC;CACzD;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,QAAQ,EAAE,qBAAqB,CAAC;IACzC,QAAQ,CAAC,GAAG,EAAE,UAAU,GAAG,OAAO,CAAC,aAAa,CAAC,CAAC;CACnD;AAED,qBAAa,gBAAiB,SAAQ,KAAK;aAGvB,QAAQ,EAAE,qBAAqB;aAC/B,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW;aAEtC,MAAM,CAAC,EAAE,MAAM;IALjC,SAAkB,IAAI,sBAAsB;gBAE1B,QAAQ,EAAE,qBAAqB,EAC/B,IAAI,EAAE,MAAM,GAAG,SAAS,GAAG,WAAW,EACtD,OAAO,EAAE,MAAM,EACC,MAAM,CAAC,EAAE,MAAM,YAAA;CAIlC;AAED,MAAM,MAAM,SAAS,GAAG,OAAO,KAAK,CAAC;AAUrC,wBAAgB,UAAU,CAAC,EAAE,EAAE,MAAM,GAAG,MAAM,CAE7C;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,CAE3E;AAED,wBAAgB,YAAY,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,CAE3E;AAED,4DAA4D;AAC5D,wBAAsB,QAAQ,CAC5B,QAAQ,EAAE,qBAAqB,EAC/B,SAAS,EAAE,SAAS,EACpB,GAAG,EAAE,MAAM,EACX,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,EAC/B,IAAI,EAAE,OAAO,GACZ,OAAO,CAAC,OAAO,CAAC,CAiClB;AAED,wBAAgB,SAAS,CAAC,QAAQ,EAAE,qBAAqB,EAAE,MAAM,EAAE,OAAO,GAAG,gBAAgB,CAM5F;AAED,yCAAyC;AACzC,wBAAgB,YAAY,CAAC,CAAC,EAC5B,QAAQ,EAAE,qBAAqB,EAC/B,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,EACpB,KAAK,EAAE,OAAO,GACb,CAAC,CAIH"}
|
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
export class LlmProviderError extends Error {
|
|
2
|
+
provider;
|
|
3
|
+
kind;
|
|
4
|
+
status;
|
|
5
|
+
name = 'LlmProviderError';
|
|
6
|
+
constructor(provider, kind, message, status) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.provider = provider;
|
|
9
|
+
this.kind = kind;
|
|
10
|
+
this.status = status;
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
// ---------------------------------------------------------------------------
|
|
14
|
+
// Wire-name sanitization
|
|
15
|
+
// ---------------------------------------------------------------------------
|
|
16
|
+
// Registry ids are dotted ('catalog.search_products') but Anthropic and
|
|
17
|
+
// OpenAI tool names must match ^[a-zA-Z0-9_-]{1,64}$. All adapters therefore
|
|
18
|
+
// send '__'-joined names and translate responses back through a per-request
|
|
19
|
+
// reverse map (never string surgery — ids may legitimately contain '_').
|
|
20
|
+
export function toWireName(id) {
|
|
21
|
+
return id.replace(/\./g, '__');
|
|
22
|
+
}
|
|
23
|
+
export function wireNameMap(tools) {
|
|
24
|
+
return new Map(tools.map((t) => [toWireName(t.name), t.name]));
|
|
25
|
+
}
|
|
26
|
+
export function fromWireName(wire, map) {
|
|
27
|
+
return map.get(wire) ?? wire;
|
|
28
|
+
}
|
|
29
|
+
/** Shared POST + JSON helper with uniform error mapping. */
|
|
30
|
+
export async function postJson(provider, fetchImpl, url, headers, body) {
|
|
31
|
+
let response;
|
|
32
|
+
try {
|
|
33
|
+
response = await fetchImpl(url, {
|
|
34
|
+
method: 'POST',
|
|
35
|
+
headers: { 'content-type': 'application/json', ...headers },
|
|
36
|
+
body: JSON.stringify(body),
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
throw new LlmProviderError(provider, 'network', `Could not reach the ${provider} API: ${err.message}`);
|
|
41
|
+
}
|
|
42
|
+
let json = null;
|
|
43
|
+
try {
|
|
44
|
+
json = await response.json();
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
// fall through — handled below
|
|
48
|
+
}
|
|
49
|
+
if (!response.ok) {
|
|
50
|
+
throw new LlmProviderError(provider, 'http', `${provider} API responded with HTTP ${response.status}.`, response.status);
|
|
51
|
+
}
|
|
52
|
+
if (json === null) {
|
|
53
|
+
throw new LlmProviderError(provider, 'malformed', `${provider} API returned a non-JSON body.`);
|
|
54
|
+
}
|
|
55
|
+
return json;
|
|
56
|
+
}
|
|
57
|
+
export function malformed(provider, issues) {
|
|
58
|
+
return new LlmProviderError(provider, 'malformed', `${provider} API response did not match the expected shape: ${JSON.stringify(issues).slice(0, 500)}`);
|
|
59
|
+
}
|
|
60
|
+
/** Boundary guard reused by adapters. */
|
|
61
|
+
export function parseOrThrow(provider, schema, value) {
|
|
62
|
+
const r = schema.safeParse(value);
|
|
63
|
+
if (!r.success)
|
|
64
|
+
throw malformed(provider, r.error.issues);
|
|
65
|
+
return r.data;
|
|
66
|
+
}
|
|
67
|
+
//# sourceMappingURL=provider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider.js","sourceRoot":"","sources":["../../../../src/backend/services/llm/provider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import type { PromptActionPlan, PromptActionResult, ToolContext } from '@endora-commerce/contracts';
|
|
2
|
+
import type { PromptActionToolRegistry } from './tool-registry.js';
|
|
3
|
+
/**
|
|
4
|
+
* PlanExecutorService — feature 043 US1/US2 (research §R6).
|
|
5
|
+
*
|
|
6
|
+
* Walks a confirmed plan with defense-in-depth re-validation: catalogue
|
|
7
|
+
* membership, Zod params, and the operator's LIVE permission are all checked
|
|
8
|
+
* again at execution time (a plan may be minutes old — FR-007). Execution
|
|
9
|
+
* delegates to the owning module's service through the tool handler; this
|
|
10
|
+
* module owns zero domain logic.
|
|
11
|
+
*
|
|
12
|
+
* Partial-failure semantics (FR-011): independent operations keep their
|
|
13
|
+
* outcome; one failure never rolls back a previously succeeded operation.
|
|
14
|
+
*/
|
|
15
|
+
export declare class PermissionRevoked extends Error {
|
|
16
|
+
readonly toolId: string;
|
|
17
|
+
readonly permission: string;
|
|
18
|
+
readonly name = "PermissionRevoked";
|
|
19
|
+
readonly code: "PROMPT_PERMISSION_REVOKED";
|
|
20
|
+
constructor(toolId: string, permission: string);
|
|
21
|
+
}
|
|
22
|
+
export interface ExecutorVisibility {
|
|
23
|
+
hasPermission(permission: string): Promise<boolean>;
|
|
24
|
+
isModuleInstalled(moduleId: string): Promise<boolean>;
|
|
25
|
+
}
|
|
26
|
+
/** Marker returned by tool handlers that delegate to the catalog bulk queue (US2). */
|
|
27
|
+
export interface DelegatedExecution {
|
|
28
|
+
delegated: true;
|
|
29
|
+
bulkOperationId: string;
|
|
30
|
+
}
|
|
31
|
+
export declare function isDelegatedExecution(value: unknown): value is DelegatedExecution;
|
|
32
|
+
export interface ExecutePlanResult {
|
|
33
|
+
result: PromptActionResult;
|
|
34
|
+
/** Set when at least one operation was delegated to the bulk machinery. */
|
|
35
|
+
bulkOperationId: string | null;
|
|
36
|
+
}
|
|
37
|
+
export declare class PlanExecutorService {
|
|
38
|
+
private readonly registry;
|
|
39
|
+
constructor(registry: PromptActionToolRegistry);
|
|
40
|
+
/**
|
|
41
|
+
* Executes every operation in the plan. Throws {@link PermissionRevoked}
|
|
42
|
+
* (the whole request becomes `refused`) when a live permission check
|
|
43
|
+
* fails BEFORE any operation has run; revocation discovered mid-plan is
|
|
44
|
+
* reported as a per-operation failure instead (already-applied work must
|
|
45
|
+
* stay applied — FR-011).
|
|
46
|
+
*/
|
|
47
|
+
execute(plan: PromptActionPlan, toolCtx: ToolContext, visibility: ExecutorVisibility): Promise<ExecutePlanResult>;
|
|
48
|
+
}
|
|
49
|
+
//# sourceMappingURL=plan-executor.service.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan-executor.service.d.ts","sourceRoot":"","sources":["../../../src/backend/services/plan-executor.service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,kBAAkB,EAElB,WAAW,EACZ,MAAM,4BAA4B,CAAC;AACpC,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,oBAAoB,CAAC;AAEnE;;;;;;;;;;;GAWG;AAEH,qBAAa,iBAAkB,SAAQ,KAAK;aAGd,MAAM,EAAE,MAAM;aAAkB,UAAU,EAAE,MAAM;IAF9E,SAAkB,IAAI,uBAAuB;IAC7C,QAAQ,CAAC,IAAI,EAAG,2BAA2B,CAAU;gBACzB,MAAM,EAAE,MAAM,EAAkB,UAAU,EAAE,MAAM;CAG/E;AAED,MAAM,WAAW,kBAAkB;IACjC,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;IACpD,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,CAAC;CACvD;AAED,sFAAsF;AACtF,MAAM,WAAW,kBAAkB;IACjC,SAAS,EAAE,IAAI,CAAC;IAChB,eAAe,EAAE,MAAM,CAAC;CACzB;AAED,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI,kBAAkB,CAOhF;AAiBD,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,kBAAkB,CAAC;IAC3B,2EAA2E;IAC3E,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;CAChC;AAED,qBAAa,mBAAmB;IAClB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,wBAAwB;IAE/D;;;;;;OAMG;IACG,OAAO,CACX,IAAI,EAAE,gBAAgB,EACtB,OAAO,EAAE,WAAW,EACpB,UAAU,EAAE,kBAAkB,GAC7B,OAAO,CAAC,iBAAiB,CAAC;CA+E9B"}
|