@agentforge-io/core 2.0.5 → 2.0.7

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.
@@ -17,6 +17,27 @@ export declare class AgentRunnerService {
17
17
  });
18
18
  run(agent: AgentDefinition, messages: AnthropicMessage[], context: ToolExecutionContext, overrides?: AgentOverrides): Promise<AgentResponse>;
19
19
  stream(agent: AgentDefinition, messages: AnthropicMessage[], context: ToolExecutionContext, overrides?: AgentOverrides): AsyncGenerator<StreamChunk>;
20
+ /**
21
+ * Compose the system prompt for a single Anthropic call:
22
+ *
23
+ * [tool-awareness preamble] ← only when `tools` is non-empty
24
+ * ──────────────────────────
25
+ * agent.systemPrompt ← what the operator wrote
26
+ * ──────────────────────────
27
+ * overrides.systemPromptSuffix ← optional per-call addendum
28
+ *
29
+ * The preamble exists because operator prompts in the wild often pin
30
+ * the model to a narrow persona ("respond in three sentences", "stick
31
+ * to product Q&A") which suppresses tool use even when tools are
32
+ * attached and clearly relevant. The preamble doesn't override the
33
+ * operator — it's a short, generic reminder that listed tools are
34
+ * available and should be consulted when the user's question depends
35
+ * on real-world / current / authoritative information.
36
+ *
37
+ * It's only added when tools are present, so prompt-only agents stay
38
+ * exactly as the operator wrote them.
39
+ */
40
+ private buildSystemPrompt;
20
41
  /**
21
42
  * Merge `agent.tools[]` (resolved via the global registry) with any
22
43
  * per-call extras (e.g. the user's connector tools).
@@ -30,10 +30,8 @@ class AgentRunnerService {
30
30
  const model = overrides?.model ?? agent.model ?? this.anthropicConfig.defaultModel ?? 'claude-opus-4-6';
31
31
  const maxTokens = overrides?.maxTokens ?? agent.maxTokens ?? this.anthropicConfig.defaultMaxTokens ?? 4096;
32
32
  const temperature = overrides?.temperature ?? agent.temperature ?? 1;
33
- const systemPrompt = overrides?.systemPromptSuffix
34
- ? `${agent.systemPrompt}\n\n${overrides.systemPromptSuffix}`
35
- : agent.systemPrompt;
36
33
  const { tools, extras } = this.buildToolList(agent, overrides);
34
+ const systemPrompt = this.buildSystemPrompt(agent, tools, overrides);
37
35
  const toolCalls = [];
38
36
  let currentMessages = [...messages];
39
37
  let totalUsage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
@@ -117,10 +115,8 @@ class AgentRunnerService {
117
115
  const model = overrides?.model ?? agent.model ?? this.anthropicConfig.defaultModel ?? 'claude-opus-4-6';
118
116
  const maxTokens = overrides?.maxTokens ?? agent.maxTokens ?? this.anthropicConfig.defaultMaxTokens ?? 4096;
119
117
  const temperature = overrides?.temperature ?? agent.temperature ?? 1;
120
- const systemPrompt = overrides?.systemPromptSuffix
121
- ? `${agent.systemPrompt}\n\n${overrides.systemPromptSuffix}`
122
- : agent.systemPrompt;
123
118
  const { tools, extras } = this.buildToolList(agent, overrides);
119
+ const systemPrompt = this.buildSystemPrompt(agent, tools, overrides);
124
120
  let currentMessages = [...messages];
125
121
  let totalUsage = { inputTokens: 0, outputTokens: 0, totalTokens: 0 };
126
122
  while (true) {
@@ -184,6 +180,44 @@ class AgentRunnerService {
184
180
  yield { type: 'usage', usage: totalUsage };
185
181
  yield { type: 'done', messageId };
186
182
  }
183
+ /**
184
+ * Compose the system prompt for a single Anthropic call:
185
+ *
186
+ * [tool-awareness preamble] ← only when `tools` is non-empty
187
+ * ──────────────────────────
188
+ * agent.systemPrompt ← what the operator wrote
189
+ * ──────────────────────────
190
+ * overrides.systemPromptSuffix ← optional per-call addendum
191
+ *
192
+ * The preamble exists because operator prompts in the wild often pin
193
+ * the model to a narrow persona ("respond in three sentences", "stick
194
+ * to product Q&A") which suppresses tool use even when tools are
195
+ * attached and clearly relevant. The preamble doesn't override the
196
+ * operator — it's a short, generic reminder that listed tools are
197
+ * available and should be consulted when the user's question depends
198
+ * on real-world / current / authoritative information.
199
+ *
200
+ * It's only added when tools are present, so prompt-only agents stay
201
+ * exactly as the operator wrote them.
202
+ */
203
+ buildSystemPrompt(agent, tools, overrides) {
204
+ const parts = [];
205
+ if (tools && tools.length > 0) {
206
+ const names = tools.map((t) => `\`${t.name}\``).join(', ');
207
+ parts.push('You have the following tools available: ' +
208
+ names +
209
+ '. Use them whenever the user’s request depends on information ' +
210
+ 'you can’t reliably produce from memory (current data, time, ' +
211
+ 'account-specific facts, external APIs). Do not refuse to use a ' +
212
+ 'tool because of style or persona instructions further below — ' +
213
+ 'those control your voice, not your capabilities. When a tool is ' +
214
+ 'clearly relevant, call it before composing the final answer.');
215
+ }
216
+ parts.push(agent.systemPrompt);
217
+ if (overrides?.systemPromptSuffix)
218
+ parts.push(overrides.systemPromptSuffix);
219
+ return parts.join('\n\n');
220
+ }
187
221
  /**
188
222
  * Merge `agent.tools[]` (resolved via the global registry) with any
189
223
  * per-call extras (e.g. the user's connector tools).
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@agentforge-io/core",
3
- "version": "2.0.5",
3
+ "version": "2.0.7",
4
4
  "description": "Framework-free AI runtime SDK. Owns: agent loop (Anthropic), conversations, tools, streaming, agent-job queue, SdkHooks. Identity, billing, infra (email/uploads/secrets) live in the host's modules — not here.",
5
5
  "license": "MIT",
6
6
  "main": "dist/index.js",