@cap-js/agents 0.9.3 → 0.9.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/_i18n/messages.properties +17 -0
- package/cds-plugin.js +94 -77
- package/lib/agents/markdown/deep-agent.js +1 -1
- package/lib/agents/middleware/hitl-decision-note-injector.js +18 -0
- package/lib/agents/middleware/hitl.js +2 -2
- package/lib/agents/middleware/index.js +1 -1
- package/lib/agents/middleware/quota-enforcer.js +17 -8
- package/lib/agents/middleware/remote-mcp.js +3 -2
- package/lib/agents/middleware/status-update.js +1 -1
- package/lib/agents/middleware/tool-wrap.js +5 -6
- package/lib/agents/quota-enforcer-at-start.js +21 -18
- package/lib/agents/summarize-on-timeout.js +18 -13
- package/lib/compile.js +2 -3
- package/lib/config/local.js +94 -0
- package/lib/eval/eval-run.js +11 -6
- package/lib/index.js +9 -12
- package/lib/models/aicore.js +91 -127
- package/lib/models/anthropic.js +10 -67
- package/lib/preview/chat.html +62 -33
- package/lib/telemetry/chat-tracing.js +13 -3
- package/lib/telemetry/metrics.js +6 -0
- package/lib/telemetry/mlflow/exporter/DatabricksExporter.js +1 -1
- package/lib/telemetry/mlflow/prompts.js +6 -2
- package/lib/utils/caching.js +132 -0
- package/lib/utils/message-handling.js +14 -0
- package/lib/utils/utils.js +4 -9
- package/package.json +7 -5
- package/srv/handlers/chat.js +4 -4
- package/srv/handlers/graph-executor/hitl.js +381 -0
- package/srv/handlers/graph-executor.js +99 -336
- package/srv/handlers/index.js +4 -3
- package/srv/handlers/mcp-tools.js +3 -2
- package/srv/handlers/{sub-agent-tools.js → subagent-tools.js} +43 -22
- package/srv/handlers/tools.js +35 -9
- package/lib/agents/middleware/hitl-edit-note-injector.js +0 -18
package/lib/preview/chat.html
CHANGED
|
@@ -126,6 +126,15 @@
|
|
|
126
126
|
letter-spacing: 0.03em;
|
|
127
127
|
text-transform: uppercase;
|
|
128
128
|
}
|
|
129
|
+
.msg.approval pre {
|
|
130
|
+
margin: 8px 0 0;
|
|
131
|
+
padding: 8px;
|
|
132
|
+
overflow-x: auto;
|
|
133
|
+
border-radius: 6px;
|
|
134
|
+
background: #e7f4ff;
|
|
135
|
+
font-size: 1.1em;
|
|
136
|
+
white-space: pre;
|
|
137
|
+
}
|
|
129
138
|
|
|
130
139
|
.msg.agent p {
|
|
131
140
|
margin: 0 0 6px;
|
|
@@ -371,6 +380,9 @@
|
|
|
371
380
|
.msg.approval::before {
|
|
372
381
|
color: #91adc5;
|
|
373
382
|
}
|
|
383
|
+
.msg.approval pre {
|
|
384
|
+
background: #0f2d45;
|
|
385
|
+
}
|
|
374
386
|
.btn-approve {
|
|
375
387
|
background: #537492;
|
|
376
388
|
}
|
|
@@ -616,7 +628,7 @@
|
|
|
616
628
|
function flushPendingThinkingUpdate() {
|
|
617
629
|
const pending = pendingThinkingUpdate
|
|
618
630
|
clearPendingThinkingUpdate()
|
|
619
|
-
if (pending) renderThinkingStep(pending
|
|
631
|
+
if (pending) renderThinkingStep(pending)
|
|
620
632
|
}
|
|
621
633
|
|
|
622
634
|
function prefersReducedMotion() {
|
|
@@ -642,10 +654,17 @@
|
|
|
642
654
|
else expandThinkingSummary(el)
|
|
643
655
|
}
|
|
644
656
|
|
|
645
|
-
function renderThinkingStep(
|
|
657
|
+
function renderThinkingStep(update) {
|
|
658
|
+
const { artifactId, text, lastChunk, append } = update
|
|
646
659
|
const panel = ensureThinkingSummary()
|
|
647
|
-
const
|
|
648
|
-
if (
|
|
660
|
+
const idx = thinkingStepEls.findIndex((step) => step._artifactId === artifactId)
|
|
661
|
+
if (append && idx >= 0) {
|
|
662
|
+
thinkingTexts[idx] += text
|
|
663
|
+
thinkingStepEls[idx].innerHTML = md(thinkingTexts[idx])
|
|
664
|
+
} else if (artifactId === currentThinkingArtifactId && !currentThinkingClosed) {
|
|
665
|
+
thinkingTexts[idx] += "\n" + text
|
|
666
|
+
thinkingStepEls[idx].innerHTML = md(thinkingTexts[idx])
|
|
667
|
+
} else {
|
|
649
668
|
const step = document.createElement("div")
|
|
650
669
|
step.className = "thinking-step"
|
|
651
670
|
step._artifactId = artifactId
|
|
@@ -657,17 +676,12 @@
|
|
|
657
676
|
updateThinkingSummaryLabel()
|
|
658
677
|
currentThinkingArtifactId = artifactId
|
|
659
678
|
currentThinkingClosed = false
|
|
660
|
-
} else {
|
|
661
|
-
// Append to current open step for this artifactId
|
|
662
|
-
const idx = thinkingStepEls.length - 1
|
|
663
|
-
thinkingTexts[idx] += text
|
|
664
|
-
thinkingStepEls[idx].innerHTML = md(thinkingTexts[idx])
|
|
665
679
|
}
|
|
666
680
|
if (lastChunk) currentThinkingClosed = true
|
|
667
681
|
messages.scrollTop = messages.scrollHeight
|
|
668
682
|
}
|
|
669
683
|
|
|
670
|
-
function addThinkingStep(artifactId, text, lastChunk) {
|
|
684
|
+
function addThinkingStep(artifactId, text, lastChunk, append) {
|
|
671
685
|
if (
|
|
672
686
|
pendingThinkingUpdate &&
|
|
673
687
|
pendingThinkingUpdate.artifactId === artifactId &&
|
|
@@ -677,7 +691,7 @@
|
|
|
677
691
|
pendingThinkingUpdate.lastChunk = lastChunk
|
|
678
692
|
} else {
|
|
679
693
|
flushPendingThinkingUpdate()
|
|
680
|
-
pendingThinkingUpdate = { artifactId, text, lastChunk }
|
|
694
|
+
pendingThinkingUpdate = { artifactId, text, lastChunk, append }
|
|
681
695
|
}
|
|
682
696
|
|
|
683
697
|
if (pendingThinkingTimer) clearTimeout(pendingThinkingTimer)
|
|
@@ -808,31 +822,41 @@
|
|
|
808
822
|
setTimeout(finish, THINKING_SUMMARY_ANIMATION_MS + 80)
|
|
809
823
|
}
|
|
810
824
|
|
|
811
|
-
function addApprovalPrompt(description) {
|
|
825
|
+
function addApprovalPrompt(description, options, actionRequest) {
|
|
812
826
|
const el = document.createElement("div")
|
|
813
827
|
el.className = "msg approval"
|
|
814
|
-
|
|
828
|
+
const content = document.createElement("div")
|
|
829
|
+
content.textContent = actionRequest?.name
|
|
830
|
+
? `Tool execution requires approval\n\nTool: ${actionRequest.name}`
|
|
831
|
+
: description || "The agent requires your approval to continue."
|
|
832
|
+
el.appendChild(content)
|
|
833
|
+
content.innerHTML = md(content.textContent)
|
|
834
|
+
if (actionRequest?.args !== undefined) {
|
|
835
|
+
const json = document.createElement("pre")
|
|
836
|
+
json.textContent = JSON.stringify(actionRequest.args, null, 2)
|
|
837
|
+
el.appendChild(json)
|
|
838
|
+
}
|
|
815
839
|
const actions = document.createElement("div")
|
|
816
840
|
actions.className = "approval-actions"
|
|
817
841
|
|
|
818
|
-
const
|
|
819
|
-
|
|
820
|
-
|
|
821
|
-
|
|
822
|
-
|
|
823
|
-
|
|
824
|
-
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
842
|
+
const choices =
|
|
843
|
+
Array.isArray(options) && options.length
|
|
844
|
+
? options
|
|
845
|
+
: [
|
|
846
|
+
{ value: "approve", label: "Approve" },
|
|
847
|
+
{ value: "reject", label: "Reject" },
|
|
848
|
+
]
|
|
849
|
+
for (const option of choices) {
|
|
850
|
+
if (typeof option?.value !== "string" || typeof option?.label !== "string") continue
|
|
851
|
+
const button = document.createElement("button")
|
|
852
|
+
button.className = option.value === "reject" ? "btn-reject" : "btn-approve"
|
|
853
|
+
button.textContent = option.label
|
|
854
|
+
button.addEventListener("click", () => {
|
|
855
|
+
removeApprovalPrompt(el)
|
|
856
|
+
resume(option.value)
|
|
857
|
+
})
|
|
858
|
+
actions.appendChild(button)
|
|
859
|
+
}
|
|
836
860
|
el.appendChild(actions)
|
|
837
861
|
messages.insertBefore(el, typing.parentElement === messages ? typing : statusText)
|
|
838
862
|
messages.scrollTop = messages.scrollHeight
|
|
@@ -924,8 +948,12 @@
|
|
|
924
948
|
pendingTaskId = taskId
|
|
925
949
|
const msgParts = result?.status?.message?.parts ?? []
|
|
926
950
|
const description = partsToText(msgParts)
|
|
951
|
+
const options =
|
|
952
|
+
result?.status?.message?.metadata?.["sap.cds.agents.input-required"]?.options
|
|
953
|
+
const actionRequest = msgParts.find((part) => part.kind === "data")?.data
|
|
954
|
+
?.actionRequests?.[0]
|
|
927
955
|
flushPendingThinkingUpdate()
|
|
928
|
-
addApprovalPrompt(description)
|
|
956
|
+
addApprovalPrompt(description, options, actionRequest)
|
|
929
957
|
return
|
|
930
958
|
}
|
|
931
959
|
|
|
@@ -1100,7 +1128,8 @@
|
|
|
1100
1128
|
|
|
1101
1129
|
if (event.artifact?.artifactId?.startsWith("thinking")) {
|
|
1102
1130
|
const lastChunk = event.lastChunk ?? false
|
|
1103
|
-
if (text)
|
|
1131
|
+
if (text)
|
|
1132
|
+
addThinkingStep(event.artifact.artifactId, text, lastChunk, event.append ?? false)
|
|
1104
1133
|
return null
|
|
1105
1134
|
}
|
|
1106
1135
|
|
|
@@ -62,7 +62,7 @@ export function _patchChatModelProto(proto) {
|
|
|
62
62
|
const provider = _resolveProvider()
|
|
63
63
|
const node = opts?.runName || "agent"
|
|
64
64
|
const messages = Array.isArray(input) ? input : undefined
|
|
65
|
-
const cacheControl =
|
|
65
|
+
const cacheControl = _detectCacheRequest({ messages, opts, modelOptions: this.options })
|
|
66
66
|
const streaming = this.streaming || this.orchestrationConfig?.streaming || false
|
|
67
67
|
const mAttrs = _metricAttrs(model, node)
|
|
68
68
|
|
|
@@ -162,8 +162,18 @@ function _metricAttrs(model, node) {
|
|
|
162
162
|
}
|
|
163
163
|
}
|
|
164
164
|
|
|
165
|
-
|
|
166
|
-
|
|
165
|
+
function _detectCacheRequest({ messages, opts, modelOptions }) {
|
|
166
|
+
const params = modelOptions?.params
|
|
167
|
+
return Boolean(
|
|
168
|
+
_messagesHaveCacheControl(messages) ||
|
|
169
|
+
opts?.cache_control ||
|
|
170
|
+
modelOptions?.promptCaching ||
|
|
171
|
+
params?.prompt_cache_retention ||
|
|
172
|
+
params?.prompt_cache_options,
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
function _messagesHaveCacheControl(messages) {
|
|
167
177
|
if (!Array.isArray(messages)) return false
|
|
168
178
|
return messages.some((m) => {
|
|
169
179
|
if (!Array.isArray(m.content)) return false
|
package/lib/telemetry/metrics.js
CHANGED
|
@@ -53,6 +53,12 @@ export const llmInvocations = meter.createCounter("agent.llm.invocations", {
|
|
|
53
53
|
export const toolInvocations = meter.createCounter("agent.tool.invocations", {
|
|
54
54
|
description: "Tool invocation count",
|
|
55
55
|
})
|
|
56
|
+
export const hitlGates = meter.createCounter("agent.hitl.gates", {
|
|
57
|
+
description: "HITL action gates requested",
|
|
58
|
+
})
|
|
59
|
+
export const hitlDecisions = meter.createCounter("agent.hitl.decisions", {
|
|
60
|
+
description: "HITL decisions by action",
|
|
61
|
+
})
|
|
56
62
|
|
|
57
63
|
/** Common attributes for all agent metrics */
|
|
58
64
|
export function attrs(srv) {
|
|
@@ -11,7 +11,7 @@ export class DatabricksExporter extends MlflowExporter {
|
|
|
11
11
|
) {
|
|
12
12
|
const { uc, warehouseId } = this._creds
|
|
13
13
|
const ucPrefix = `${uc.catalog}.${uc.schema}.${uc.tablePrefix}`
|
|
14
|
-
let url = `/api/4.0/mlflow/traces/${encodeURIComponent(ucPrefix)}
|
|
14
|
+
let url = `/api/4.0/mlflow/traces/${encodeURIComponent(ucPrefix)}/${traceId}/assessments`
|
|
15
15
|
if (warehouseId) url += `?sql_warehouse_id=${encodeURIComponent(warehouseId)}`
|
|
16
16
|
await this._fetch(url, {
|
|
17
17
|
trace_id: traceId,
|
|
@@ -71,9 +71,9 @@ export function syncSystemPrompt(messages) {
|
|
|
71
71
|
export function resolvePromptName(srv) {
|
|
72
72
|
if (!srv?.name) return ""
|
|
73
73
|
const agentDir = resolveAgentDir(srv)
|
|
74
|
-
if (!agentDir) return srv.name
|
|
74
|
+
if (!agentDir) return _mlflowName(srv.name)
|
|
75
75
|
const root = cds.root ?? process.cwd()
|
|
76
|
-
return relative(root, join(agentDir, "AGENTS.md")).replace(/\\/g, "/")
|
|
76
|
+
return _mlflowName(relative(root, join(agentDir, "AGENTS.md")).replace(/\\/g, "/"))
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
export function hashPrompt(text) {
|
|
@@ -88,6 +88,10 @@ function _description(name) {
|
|
|
88
88
|
return `System prompt for CAP agent service "${name.split("/")[0]}"`
|
|
89
89
|
}
|
|
90
90
|
|
|
91
|
+
function _mlflowName(name) {
|
|
92
|
+
return String(name).replace(/[\\/.:]/g, "_")
|
|
93
|
+
}
|
|
94
|
+
|
|
91
95
|
function _registrationTags() {
|
|
92
96
|
return [{ key: "mlflow.prompt.is_prompt", value: "true" }]
|
|
93
97
|
}
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import cds from "@sap/cds"
|
|
2
|
+
|
|
3
|
+
export const PROMPT_CACHE_MODEL_PARAMS = Symbol("promptCacheModelParams")
|
|
4
|
+
|
|
5
|
+
const CACHE_CONTROL_EPHEMERAL = { type: "ephemeral" }
|
|
6
|
+
|
|
7
|
+
export function isPromptCachingModel(model) {
|
|
8
|
+
return promptCachingMode(model) !== undefined
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export function withPromptCachingParams(model, params) {
|
|
12
|
+
if (params !== undefined && (typeof params !== "object" || Array.isArray(params))) return params
|
|
13
|
+
const mode = promptCachingMode(model)
|
|
14
|
+
const base = params || {}
|
|
15
|
+
if (mode === "gpt-implicit") {
|
|
16
|
+
return {
|
|
17
|
+
...base,
|
|
18
|
+
...(base.prompt_cache_options === undefined
|
|
19
|
+
? { prompt_cache_options: { mode: "implicit", ttl: "30m" } }
|
|
20
|
+
: {}),
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
if (mode === "gpt-retention") {
|
|
24
|
+
return {
|
|
25
|
+
...base,
|
|
26
|
+
...(base.prompt_cache_retention === undefined ? { prompt_cache_retention: "24h" } : {}),
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
return params
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
export function withPromptCachingMessages(model, messages, opts) {
|
|
33
|
+
if (promptCachingMode(model) !== "claude") return { messages, opts }
|
|
34
|
+
|
|
35
|
+
const cachedMessages = [...messages]
|
|
36
|
+
addCacheControlToLast(cachedMessages, "system")
|
|
37
|
+
addCacheControlToLast(cachedMessages, "ai")
|
|
38
|
+
addCacheControlToLast(cachedMessages, "human")
|
|
39
|
+
|
|
40
|
+
if (!opts?.tools?.length) return { messages: cachedMessages, opts }
|
|
41
|
+
const tools = [...opts.tools]
|
|
42
|
+
tools[tools.length - 1] = { ...tools[tools.length - 1], cache_control: CACHE_CONTROL_EPHEMERAL }
|
|
43
|
+
return { messages: cachedMessages, opts: { ...opts, tools } }
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export function withPromptCachingOptions(model, opts) {
|
|
47
|
+
const mode = promptCachingMode(model)
|
|
48
|
+
if (mode === "nova" && !opts?.cache_control) {
|
|
49
|
+
return { ...opts, cache_control: CACHE_CONTROL_EPHEMERAL }
|
|
50
|
+
}
|
|
51
|
+
if (!isGptCachingMode(mode)) return opts
|
|
52
|
+
|
|
53
|
+
const params = opts?.[PROMPT_CACHE_MODEL_PARAMS] || {}
|
|
54
|
+
if (params.prompt_cache_key !== undefined) return opts
|
|
55
|
+
return {
|
|
56
|
+
...opts,
|
|
57
|
+
[PROMPT_CACHE_MODEL_PARAMS]: {
|
|
58
|
+
...params,
|
|
59
|
+
prompt_cache_key: opts?.prompt_cache_key ?? buildPromptCacheKey(),
|
|
60
|
+
},
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function buildPromptCacheKey() {
|
|
65
|
+
return cds.context?.tenant || ""
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
function promptCachingMode(model) {
|
|
69
|
+
const name = String(model || "")
|
|
70
|
+
if (/anthropic|claude/i.test(name)) return "claude"
|
|
71
|
+
if (/(?:^|[-_])nova(?:[-_]|$)/i.test(name) || /amazon.*nova/i.test(name)) return "nova"
|
|
72
|
+
|
|
73
|
+
const version = gptVersion(name)
|
|
74
|
+
if (!version) return undefined
|
|
75
|
+
if (version.major > 5 || (version.major === 5 && version.minor >= 6)) return "gpt-implicit"
|
|
76
|
+
if ((version.major === 5 && version.minor < 6) || (version.major === 4 && version.minor === 1)) {
|
|
77
|
+
return "gpt-retention"
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
function isGptCachingMode(mode) {
|
|
82
|
+
return mode === "gpt-implicit" || mode === "gpt-retention"
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
function gptVersion(model) {
|
|
86
|
+
const match = model.match(/(?:^|[^a-z0-9])gpt[-_]?([0-9]+)(?:[._-]([0-9]+))?/i)
|
|
87
|
+
return match && { major: Number(match[1]), minor: Number(match[2] || 0) }
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
function addCacheControlToLast(messages, type) {
|
|
91
|
+
for (let index = messages.length - 1; index >= 0; index--) {
|
|
92
|
+
if (messageType(messages[index]) === type && hasTextContent(messages[index])) {
|
|
93
|
+
messages[index] = withCacheControl(messages[index])
|
|
94
|
+
return
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function messageType(message) {
|
|
100
|
+
return message._getType?.() || message.type
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function hasTextContent(message) {
|
|
104
|
+
return (
|
|
105
|
+
(typeof message.content === "string" && message.content.length > 0) ||
|
|
106
|
+
(Array.isArray(message.content) &&
|
|
107
|
+
message.content.some((block) => block?.type === "text" && block.text?.length > 0))
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
function withCacheControl(message) {
|
|
112
|
+
const content = message.content
|
|
113
|
+
if (typeof content === "string") {
|
|
114
|
+
return cloneMessage(message, [
|
|
115
|
+
{ type: "text", text: content, cache_control: CACHE_CONTROL_EPHEMERAL },
|
|
116
|
+
])
|
|
117
|
+
}
|
|
118
|
+
if (!Array.isArray(content)) return message
|
|
119
|
+
|
|
120
|
+
for (let index = content.length - 1; index >= 0; index--) {
|
|
121
|
+
if (content[index]?.type === "text") {
|
|
122
|
+
const nextContent = [...content]
|
|
123
|
+
nextContent[index] = { ...nextContent[index], cache_control: CACHE_CONTROL_EPHEMERAL }
|
|
124
|
+
return cloneMessage(message, nextContent)
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
return message
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
function cloneMessage(message, content) {
|
|
131
|
+
return Object.assign(Object.create(Object.getPrototypeOf(message)), message, { content })
|
|
132
|
+
}
|
|
@@ -1,3 +1,17 @@
|
|
|
1
|
+
import { randomUUID } from "node:crypto"
|
|
2
|
+
|
|
3
|
+
export function agentMessage(text, data, metadata) {
|
|
4
|
+
const parts = [{ kind: "text", text }]
|
|
5
|
+
if (data && typeof data === "object") parts.push({ kind: "data", data })
|
|
6
|
+
return {
|
|
7
|
+
kind: "message",
|
|
8
|
+
messageId: randomUUID(),
|
|
9
|
+
role: "agent",
|
|
10
|
+
parts,
|
|
11
|
+
...(metadata && { metadata }),
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
1
15
|
/**
|
|
2
16
|
* A2A message part utilities — handle both wire formats:
|
|
3
17
|
*
|
package/lib/utils/utils.js
CHANGED
|
@@ -10,12 +10,6 @@ function resolveI18n(value, locale) {
|
|
|
10
10
|
return value
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
export function getAgentLogger(srv) {
|
|
14
|
-
const slug = slugified(srv.name)
|
|
15
|
-
const agentSlug = slug.endsWith("-agent") ? slug : `${slug}-agent`
|
|
16
|
-
return cds.log("agents:" + srv.name, { label: agentSlug })
|
|
17
|
-
}
|
|
18
|
-
|
|
19
13
|
/**
|
|
20
14
|
* Mirrors CAP's internal slug rules used for service path generation.
|
|
21
15
|
*/
|
|
@@ -57,10 +51,11 @@ export function getFilteredEntities(srv) {
|
|
|
57
51
|
Object.entries(srv.entities || {})
|
|
58
52
|
.filter(
|
|
59
53
|
([name, entity]) =>
|
|
60
|
-
!
|
|
54
|
+
!entity["@cds.autoexposed"] &&
|
|
55
|
+
!entity["@cds.api.ignore"] &&
|
|
61
56
|
!name.endsWith("DraftAdministrativeData") &&
|
|
62
|
-
!name.endsWith(".
|
|
63
|
-
!
|
|
57
|
+
!name.endsWith(".drafts") &&
|
|
58
|
+
!name.endsWith(".texts"),
|
|
64
59
|
)
|
|
65
60
|
.sort(([a], [b]) => a.localeCompare(b)),
|
|
66
61
|
)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cap-js/agents",
|
|
3
|
-
"version": "0.9.
|
|
3
|
+
"version": "0.9.5",
|
|
4
4
|
"description": "CDS plugin for building agents",
|
|
5
5
|
"author": "SAP SE (https://www.sap.com)",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
],
|
|
42
42
|
"dependencies": {
|
|
43
43
|
"@a2a-js/sdk": "^0.3.12",
|
|
44
|
-
"@cap-js/attachments": "
|
|
44
|
+
"@cap-js/attachments": ">=3",
|
|
45
45
|
"@cap-js/mcp": "^1.4",
|
|
46
46
|
"@langchain/anthropic": "^1.5.1",
|
|
47
47
|
"@langchain/core": "^1",
|
|
@@ -147,7 +147,7 @@
|
|
|
147
147
|
"image/jpeg"
|
|
148
148
|
]
|
|
149
149
|
},
|
|
150
|
-
"
|
|
150
|
+
"quotas": {
|
|
151
151
|
"maxConcurrentTasks": 10,
|
|
152
152
|
"maxConcurrentTasksPerUser": 4,
|
|
153
153
|
"maxTasksPerHour": 100,
|
|
@@ -159,7 +159,6 @@
|
|
|
159
159
|
"maxLLMTokensPerTask": 200000,
|
|
160
160
|
"maxLLMCallTimeout": "120s",
|
|
161
161
|
"maxExecutionTimePerTask": "5min",
|
|
162
|
-
"timeoutGrace": "15s",
|
|
163
162
|
"maxIncomingMessageLength": 5000
|
|
164
163
|
}
|
|
165
164
|
},
|
|
@@ -190,7 +189,7 @@
|
|
|
190
189
|
}
|
|
191
190
|
},
|
|
192
191
|
"[development]": {
|
|
193
|
-
"llm": "
|
|
192
|
+
"llm": "auto"
|
|
194
193
|
},
|
|
195
194
|
"[with-claude]": {
|
|
196
195
|
"llm": "anthropic"
|
|
@@ -217,6 +216,9 @@
|
|
|
217
216
|
"_javaHcqlCompat": true
|
|
218
217
|
}
|
|
219
218
|
}
|
|
219
|
+
},
|
|
220
|
+
"folders": {
|
|
221
|
+
"srvs": "srv/*"
|
|
220
222
|
}
|
|
221
223
|
},
|
|
222
224
|
"workspaces": [
|
package/srv/handlers/chat.js
CHANGED
|
@@ -73,7 +73,7 @@ function toolCallsFromMessages(messages) {
|
|
|
73
73
|
for (const msg of messages) {
|
|
74
74
|
if (msg.tool_call_id && msg.type === "tool") {
|
|
75
75
|
const content = typeof msg.content === "string" ? msg.content : JSON.stringify(msg.content)
|
|
76
|
-
resultById.set(msg.tool_call_id, content)
|
|
76
|
+
resultById.set(msg.tool_call_id, { content, ...msg })
|
|
77
77
|
}
|
|
78
78
|
}
|
|
79
79
|
|
|
@@ -84,14 +84,14 @@ function toolCallsFromMessages(messages) {
|
|
|
84
84
|
const raw = resultById.get(tc.id)
|
|
85
85
|
let toolResult
|
|
86
86
|
try {
|
|
87
|
-
toolResult = raw !== undefined ? JSON.parse(raw) : undefined
|
|
87
|
+
toolResult = raw?.content !== undefined ? JSON.parse(raw.content) : undefined
|
|
88
88
|
} catch {
|
|
89
|
-
toolResult = raw
|
|
89
|
+
toolResult = raw?.content
|
|
90
90
|
}
|
|
91
91
|
const entry = {
|
|
92
92
|
tool: tc.name,
|
|
93
93
|
args: tc.args ?? {},
|
|
94
|
-
outcome:
|
|
94
|
+
outcome: raw.status,
|
|
95
95
|
...(toolResult !== undefined && { result: toolResult }),
|
|
96
96
|
}
|
|
97
97
|
attachCqn(entry)
|