pi-sap-aicore 0.3.1 → 0.3.2
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/CHANGELOG.md
CHANGED
|
@@ -7,6 +7,17 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
7
7
|
|
|
8
8
|
## [Unreleased]
|
|
9
9
|
|
|
10
|
+
## [0.3.2] - 2026-07-01
|
|
11
|
+
|
|
12
|
+
### Fixed
|
|
13
|
+
|
|
14
|
+
- Direct AWS Bedrock and GCP Vertex AI foundation routes now advertise pi tools
|
|
15
|
+
using provider-native tool/function declaration schemas, so Claude and Gemini
|
|
16
|
+
foundation models can perform real coding-agent tool calls instead of acting as
|
|
17
|
+
text-only generators.
|
|
18
|
+
- Vertex/Gemini foundation tool-call replay now preserves Gemini thought signatures
|
|
19
|
+
and normalizes provider-prefixed function names before emitting pi tool calls.
|
|
20
|
+
|
|
10
21
|
## [0.3.1] - 2026-07-01
|
|
11
22
|
|
|
12
23
|
### Added
|
|
@@ -135,7 +146,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
135
146
|
`reasoning_effort` for OpenAI).
|
|
136
147
|
- MIT license and npm packaging.
|
|
137
148
|
|
|
138
|
-
[Unreleased]: https://github.com/ttiimmaahh/pi-sap-aicore/compare/v0.3.
|
|
149
|
+
[Unreleased]: https://github.com/ttiimmaahh/pi-sap-aicore/compare/v0.3.2...HEAD
|
|
150
|
+
[0.3.2]: https://github.com/ttiimmaahh/pi-sap-aicore/compare/v0.3.1...v0.3.2
|
|
139
151
|
[0.3.1]: https://github.com/ttiimmaahh/pi-sap-aicore/compare/v0.3.0...v0.3.1
|
|
140
152
|
[0.3.0]: https://github.com/ttiimmaahh/pi-sap-aicore/compare/v0.2.2...v0.3.0
|
|
141
153
|
[0.2.2]: https://github.com/ttiimmaahh/pi-sap-aicore/compare/v0.2.1...v0.2.2
|
package/README.md
CHANGED
|
@@ -132,8 +132,9 @@ The extension registers **two providers**, both backed by the same service key:
|
|
|
132
132
|
|---|---|---|
|
|
133
133
|
| SAP deployment | one orchestration deployment fronts **every** model | one foundation deployment **per model** |
|
|
134
134
|
| Models | Claude, GPT-5*, Gemini | GPT/OpenAI (`azure-openai`), Anthropic/Claude (`aws-bedrock`), and Gemini (`gcp-vertexai`) |
|
|
135
|
+
| Tool use | yes | yes — tools are translated to OpenAI, Bedrock Converse, or Vertex/Gemini function declarations by executable |
|
|
135
136
|
| Streaming | subject to orchestration's per-model allow-list — new models can 400 `Streaming is not supported` (we fall back to non-streaming) | Azure OpenAI streams natively; AWS Bedrock and Vertex AI currently use non-streaming endpoints and replay responses into pi stream events |
|
|
136
|
-
| Reasoning effort | tunable (`reasoning_effort` / `thinking`) | model **default** only for Azure; Bedrock/Anthropic and Vertex/Gemini
|
|
137
|
+
| Reasoning effort | tunable (`reasoning_effort` / `thinking`) | model **default** only for Azure; Bedrock/Anthropic and Vertex/Gemini effort controls are intentionally conservative |
|
|
137
138
|
| Content filter / grounding / templating | yes | no — raw model access |
|
|
138
139
|
| SDK / endpoint | `@sap-ai-sdk/orchestration` | `AzureOpenAiChatClient` for `azure-openai`; SAP `/inference/deployments/{id}/converse` for `aws-bedrock`; SAP `/inference/deployments/{id}/models/{model}:generateContent` for `gcp-vertexai` |
|
|
139
140
|
|
|
@@ -337,7 +338,8 @@ the direct Azure OpenAI SDK pinned to API version `2024-10-21`, which has no
|
|
|
337
338
|
thinking-level cycle is a no-op there. Anthropic/Claude models use SAP's AWS
|
|
338
339
|
Bedrock `/converse` endpoint; Gemini models use SAP's Vertex AI `generateContent`
|
|
339
340
|
endpoint with `thinkingBudget: 0` by default so small pi output budgets produce
|
|
340
|
-
visible text instead of only hidden thoughts.
|
|
341
|
+
visible text instead of only hidden thoughts. Tool/function calling is supported
|
|
342
|
+
on all three direct foundation executables. Use the orchestration route if you
|
|
341
343
|
need explicit effort control.
|
|
342
344
|
|
|
343
345
|
To override budgets per model, edit `thinkingLevelMap` on the relevant entry in
|
package/package.json
CHANGED
|
@@ -29,6 +29,7 @@ type VertexGenerateContentResponse = {
|
|
|
29
29
|
role?: string;
|
|
30
30
|
parts?: Array<{
|
|
31
31
|
text?: string;
|
|
32
|
+
thoughtSignature?: string;
|
|
32
33
|
functionCall?: { name?: string; args?: unknown };
|
|
33
34
|
}>;
|
|
34
35
|
};
|
|
@@ -192,14 +193,18 @@ function replayVertexGenerateContentResponse(
|
|
|
192
193
|
|
|
193
194
|
if (part.functionCall) {
|
|
194
195
|
const contentIndex = output.content.length;
|
|
196
|
+
const providerName = part.functionCall.name ?? "";
|
|
195
197
|
const toolCall = {
|
|
196
198
|
type: "toolCall" as const,
|
|
197
199
|
id: randomUUID(),
|
|
198
|
-
name:
|
|
200
|
+
name: normalizeVertexFunctionName(providerName),
|
|
199
201
|
arguments:
|
|
200
202
|
part.functionCall.args && typeof part.functionCall.args === "object"
|
|
201
203
|
? (part.functionCall.args as Record<string, unknown>)
|
|
202
204
|
: {},
|
|
205
|
+
...(part.thoughtSignature
|
|
206
|
+
? { thoughtSignature: part.thoughtSignature }
|
|
207
|
+
: {}),
|
|
203
208
|
};
|
|
204
209
|
output.content.push(toolCall);
|
|
205
210
|
stream.push({ type: "toolcall_start", contentIndex, partial: output });
|
|
@@ -212,3 +217,8 @@ function replayVertexGenerateContentResponse(
|
|
|
212
217
|
}
|
|
213
218
|
}
|
|
214
219
|
}
|
|
220
|
+
|
|
221
|
+
function normalizeVertexFunctionName(name: string): string {
|
|
222
|
+
const index = name.indexOf(":");
|
|
223
|
+
return index >= 0 ? name.slice(index + 1) : name;
|
|
224
|
+
}
|
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
Context,
|
|
4
4
|
Message,
|
|
5
5
|
TextContent,
|
|
6
|
+
Tool,
|
|
6
7
|
ToolResultMessage,
|
|
7
8
|
UserMessage,
|
|
8
9
|
} from "@earendil-works/pi-ai";
|
|
@@ -35,9 +36,20 @@ export type BedrockConverseMessage = {
|
|
|
35
36
|
content: BedrockConverseContentBlock[];
|
|
36
37
|
};
|
|
37
38
|
|
|
39
|
+
export type BedrockToolConfig = {
|
|
40
|
+
tools: Array<{
|
|
41
|
+
toolSpec: {
|
|
42
|
+
name: string;
|
|
43
|
+
description: string;
|
|
44
|
+
inputSchema: { json: Record<string, unknown> };
|
|
45
|
+
};
|
|
46
|
+
}>;
|
|
47
|
+
};
|
|
48
|
+
|
|
38
49
|
export function piContextToBedrockConverse(context: Context): {
|
|
39
50
|
system?: Array<{ text: string }>;
|
|
40
51
|
messages: BedrockConverseMessage[];
|
|
52
|
+
toolConfig?: BedrockToolConfig;
|
|
41
53
|
} {
|
|
42
54
|
const messages: BedrockConverseMessage[] = [];
|
|
43
55
|
|
|
@@ -46,9 +58,11 @@ export function piContextToBedrockConverse(context: Context): {
|
|
|
46
58
|
if (translated) messages.push(translated);
|
|
47
59
|
}
|
|
48
60
|
|
|
61
|
+
const tools = (context.tools ?? []).map(piToolToBedrockToolSpec);
|
|
49
62
|
return {
|
|
50
63
|
...(context.systemPrompt ? { system: [{ text: context.systemPrompt }] } : {}),
|
|
51
64
|
messages: coalesceAdjacentMessages(messages),
|
|
65
|
+
...(tools.length > 0 ? { toolConfig: { tools } } : {}),
|
|
52
66
|
};
|
|
53
67
|
}
|
|
54
68
|
|
|
@@ -159,6 +173,18 @@ function imageFormatFromMimeType(mimeType: string): string {
|
|
|
159
173
|
return "png";
|
|
160
174
|
}
|
|
161
175
|
|
|
176
|
+
function piToolToBedrockToolSpec(tool: Tool): BedrockToolConfig["tools"][number] {
|
|
177
|
+
return {
|
|
178
|
+
toolSpec: {
|
|
179
|
+
name: tool.name,
|
|
180
|
+
description: tool.description,
|
|
181
|
+
inputSchema: {
|
|
182
|
+
json: tool.parameters as unknown as Record<string, unknown>,
|
|
183
|
+
},
|
|
184
|
+
},
|
|
185
|
+
};
|
|
186
|
+
}
|
|
187
|
+
|
|
162
188
|
function coalesceAdjacentMessages(
|
|
163
189
|
messages: BedrockConverseMessage[],
|
|
164
190
|
): BedrockConverseMessage[] {
|
|
@@ -3,6 +3,7 @@ import type {
|
|
|
3
3
|
Context,
|
|
4
4
|
Message,
|
|
5
5
|
TextContent,
|
|
6
|
+
Tool,
|
|
6
7
|
ToolResultMessage,
|
|
7
8
|
UserMessage,
|
|
8
9
|
} from "@earendil-works/pi-ai";
|
|
@@ -10,7 +11,7 @@ import type {
|
|
|
10
11
|
export type VertexPart =
|
|
11
12
|
| { text: string }
|
|
12
13
|
| { inlineData: { mimeType: string; data: string } }
|
|
13
|
-
| { functionCall: { name: string; args: unknown } }
|
|
14
|
+
| { functionCall: { name: string; args: unknown }; thoughtSignature?: string }
|
|
14
15
|
| { functionResponse: { name: string; response: Record<string, unknown> } };
|
|
15
16
|
|
|
16
17
|
export type VertexContent = {
|
|
@@ -18,9 +19,18 @@ export type VertexContent = {
|
|
|
18
19
|
parts: VertexPart[];
|
|
19
20
|
};
|
|
20
21
|
|
|
22
|
+
export type VertexTool = {
|
|
23
|
+
functionDeclarations: Array<{
|
|
24
|
+
name: string;
|
|
25
|
+
description: string;
|
|
26
|
+
parameters: Record<string, unknown>;
|
|
27
|
+
}>;
|
|
28
|
+
};
|
|
29
|
+
|
|
21
30
|
export function piContextToVertexGenerateContent(context: Context): {
|
|
22
31
|
systemInstruction?: { parts: Array<{ text: string }> };
|
|
23
32
|
contents: VertexContent[];
|
|
33
|
+
tools?: VertexTool[];
|
|
24
34
|
} {
|
|
25
35
|
const contents: VertexContent[] = [];
|
|
26
36
|
|
|
@@ -29,11 +39,17 @@ export function piContextToVertexGenerateContent(context: Context): {
|
|
|
29
39
|
if (translated) contents.push(translated);
|
|
30
40
|
}
|
|
31
41
|
|
|
42
|
+
const functionDeclarations = (context.tools ?? []).map(
|
|
43
|
+
piToolToVertexFunctionDeclaration,
|
|
44
|
+
);
|
|
32
45
|
return {
|
|
33
46
|
...(context.systemPrompt
|
|
34
47
|
? { systemInstruction: { parts: [{ text: context.systemPrompt }] } }
|
|
35
48
|
: {}),
|
|
36
49
|
contents: coalesceAdjacentContents(contents),
|
|
50
|
+
...(functionDeclarations.length > 0
|
|
51
|
+
? { tools: [{ functionDeclarations }] }
|
|
52
|
+
: {}),
|
|
37
53
|
};
|
|
38
54
|
}
|
|
39
55
|
|
|
@@ -68,7 +84,13 @@ function piAssistantToVertexContent(msg: AssistantMessage): VertexContent {
|
|
|
68
84
|
parts.push({ text: block.text });
|
|
69
85
|
} else if (block.type === "toolCall") {
|
|
70
86
|
parts.push({
|
|
71
|
-
functionCall: {
|
|
87
|
+
functionCall: {
|
|
88
|
+
name: block.name,
|
|
89
|
+
args: block.arguments,
|
|
90
|
+
},
|
|
91
|
+
...(block.thoughtSignature
|
|
92
|
+
? { thoughtSignature: block.thoughtSignature }
|
|
93
|
+
: {}),
|
|
72
94
|
});
|
|
73
95
|
}
|
|
74
96
|
}
|
|
@@ -111,6 +133,16 @@ function toolResultImagesAsUserParts(msg: ToolResultMessage): VertexPart[] {
|
|
|
111
133
|
}));
|
|
112
134
|
}
|
|
113
135
|
|
|
136
|
+
function piToolToVertexFunctionDeclaration(
|
|
137
|
+
tool: Tool,
|
|
138
|
+
): VertexTool["functionDeclarations"][number] {
|
|
139
|
+
return {
|
|
140
|
+
name: tool.name,
|
|
141
|
+
description: tool.description,
|
|
142
|
+
parameters: tool.parameters as unknown as Record<string, unknown>,
|
|
143
|
+
};
|
|
144
|
+
}
|
|
145
|
+
|
|
114
146
|
function coalesceAdjacentContents(contents: VertexContent[]): VertexContent[] {
|
|
115
147
|
const result: VertexContent[] = [];
|
|
116
148
|
for (const content of contents) {
|