psadk 1.4.7 → 1.4.8

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/README.md CHANGED
@@ -14,6 +14,7 @@ $ npm install psadk
14
14
 
15
15
  - **Multi-Provider LLM Support**: OpenAI, Anthropic, Google Gemini, AWS Bedrock, Azure OpenAI, and more
16
16
  - **A2A Protocol Compatible**: Build agents that work with the Agent-to-Agent protocol
17
+ - **Local Agent Mode**: Run agents fully in-process via `agent-core` — no PS API dependency required
17
18
  - **Prompt Caching**: Reduce costs and latency with built-in prompt caching support (90% cost reduction!)
18
19
  - **Custom Tools**: Create and integrate custom tools with your agents
19
20
  - **Type-Safe**: Full TypeScript support with comprehensive type definitions
@@ -25,6 +26,93 @@ The classes are documented here [Documentation](./globals.md)
25
26
 
26
27
  **New:** [Prompt Caching Guide](./docs/PROMPT_CACHING.md) - Learn how to reduce costs and latency by 90% with prompt caching
27
28
 
29
+ **New:** [Local Agent Mode](#local-agent-mode) - Run agents in-process without the PS API
30
+
31
+ ## Local Agent Mode
32
+
33
+ PSAgent now supports a **local execution mode** that runs the agent fully in-process using `agent-core`, bypassing the PS API entirely.
34
+
35
+ LLM calls are routed through the PS LLM API — only the agent orchestration loop runs locally.
36
+
37
+ ### Enabling Local Mode
38
+
39
+ Set `local: true` in your `PSAgentConfig` and add an `llm` entry to `ServiceUrls` pointing at your PS API base URL:
40
+
41
+ ```typescript
42
+ import { PSAgent, PSAgentLogger } from 'psadk';
43
+ import type { LocalAgentEvent } from 'psadk';
44
+
45
+ const agent = new PSAgent(
46
+ {
47
+ name: 'MyAgent',
48
+ description: 'A local agent',
49
+ instruction: 'You are a helpful assistant.',
50
+ model: 'gpt-4o-mini',
51
+ token: process.env.PS_API_TOKEN,
52
+ local: true, // ← enable local mode
53
+ onEvent: (event: LocalAgentEvent) => {
54
+ console.log(event.agentStatus, event.output?.response ?? event.message ?? '');
55
+ },
56
+ },
57
+ new PSAgentLogger({ prefix: 'MyAgent' }),
58
+ {
59
+ agents: 'https://dev.lionis.ai',
60
+ events: 'https://dev.lionis.ai',
61
+ llm: 'https://dev.lionis.ai', // ← LLM API base URL for local mode
62
+ },
63
+ );
64
+
65
+ const result = await agent.start({ query: 'Hello!' });
66
+ console.log(result);
67
+ ```
68
+
69
+ ### Local Agent Configuration
70
+
71
+ | Option | Type | Default | Description |
72
+ |--------|------|---------|-------------|
73
+ | `local` | `boolean` | `false` | Run the agent in-process via `agent-core` instead of the PS API |
74
+ | `onEvent` | `(event: LocalAgentEvent) => void` | — | Callback invoked for each streamed event during local execution |
75
+ | `ServiceUrls.llm` | `string` | agents URL | Base URL for the PS LLM API (e.g. `https://dev.lionis.ai`) |
76
+ | `llm_config.reasoning_effort` | `'minimal' \| 'low' \| 'medium' \| 'high'` | — | Controls model reasoning: `medium`/`high` → `reasoning: true`; `low`/`minimal` → `reasoning: false` |
77
+ | `llm_config.context_window` | `number` | `128000` | Context window size in tokens passed to the local agent runtime |
78
+ | `llm_config.max_completion_tokens` | `number` | `4096` | Max output tokens for the model |
79
+
80
+ ### LocalAgentEvent Shape
81
+
82
+ ```typescript
83
+ interface LocalAgentEvent {
84
+ agentStatus: 'pending' | 'in-progress' | 'waiting' | 'completed' | 'failed';
85
+ timestamp: number; // Unix timestamp (ms)
86
+ tool?: string; // Present when agentStatus === 'waiting'
87
+ toolInput?: { request_body: Record<string, any> }; // Tool input arguments
88
+ output?: { response: string; [key: string]: any }; // Present on 'completed'
89
+ message?: string; // Present on 'failed' or 'in-progress'
90
+ }
91
+ ```
92
+
93
+ ### Behaviour Differences in Local Mode
94
+
95
+ | Operation | Remote mode | Local mode |
96
+ |-----------|-------------|------------|
97
+ | `start()` | Submits task to PS API | Runs agent-core loop in-process |
98
+ | `resume()` | Sends tool output to PS API | No-op (tools execute in-process) |
99
+ | `cancel()` | Calls PS API cancel endpoint | Calls `agent.abort()` on the in-process agent |
100
+ | `getEvents()` | Polls PS events API | Returns in-memory event log snapshot |
101
+
102
+ ### Running the Local Agent Example
103
+
104
+ ```bash
105
+ # Build first
106
+ npm run build
107
+
108
+ # Run the example
109
+ PS_API_TOKEN=<token> PS_API_URL=https://dev.lionis.ai npm run local-agent-test
110
+ ```
111
+
112
+ See [`examples/local-agent-test.ts`](./examples/local-agent-test.ts) for a full working example with tools and event streaming.
113
+
114
+ ---
115
+
28
116
  ## Agent Core Module
29
117
 
30
118
  The `agent-core` module provides a low-level, event-driven agent runtime built on `@earendil-works/pi-ai`. This module is designed for advanced use cases where you need fine-grained control over agent execution, tool calling, and message handling.
@@ -322,6 +410,71 @@ export const movie_search_tool = new PSAgentTool({
322
410
  });
323
411
  ```
324
412
 
413
+ #### local agent - run agent in-process with event streaming
414
+
415
+ ```typescript
416
+ import { PSAgent, PSAgentLogger } from 'psadk';
417
+ import type { LocalAgentEvent } from 'psadk';
418
+ import dotenv from 'dotenv';
419
+
420
+ dotenv.config();
421
+
422
+ async function main() {
423
+ const token = process.env.PS_API_TOKEN!;
424
+ const baseUrl = process.env.PS_API_URL || 'https://dev.lionis.ai';
425
+
426
+ const agent = new PSAgent(
427
+ {
428
+ name: 'LocalHelloAgent',
429
+ description: 'A simple agent running in local mode',
430
+ instruction: 'You are a friendly assistant that greets users.',
431
+ model: 'gpt-4o-mini',
432
+ token,
433
+ local: true, // run agent-core in-process
434
+ llm_config: {
435
+ reasoning_effort: 'high', // 'medium'|'high' → reasoning: true; 'low'|'minimal' → reasoning: false
436
+ context_window: 128000, // token context window (default: 128000)
437
+ max_completion_tokens: 4096, // max output tokens (default: 4096)
438
+ },
439
+ onEvent: (event: LocalAgentEvent) => {
440
+ switch (event.agentStatus) {
441
+ case 'pending':
442
+ console.log('⏳ Agent starting...');
443
+ break;
444
+ case 'in-progress':
445
+ console.log('🔄 Agent thinking...');
446
+ break;
447
+ case 'waiting':
448
+ console.log(`🔧 Calling tool: ${event.tool}`);
449
+ console.log(' Input:', JSON.stringify(event.toolInput?.request_body));
450
+ break;
451
+ case 'completed':
452
+ console.log('✅ Done:', event.output?.response);
453
+ break;
454
+ case 'failed':
455
+ console.error('❌ Failed:', event.message);
456
+ break;
457
+ }
458
+ },
459
+ },
460
+ new PSAgentLogger({ prefix: 'LocalHelloAgent' }),
461
+ {
462
+ agents: baseUrl,
463
+ events: baseUrl,
464
+ llm: baseUrl, // LLM calls route through PS LLM API
465
+ },
466
+ );
467
+
468
+ const result = await agent.start({ query: 'Say hello!' });
469
+ console.log('Result:', result);
470
+ }
471
+
472
+ main().catch((error) => {
473
+ console.error(error);
474
+ process.exit(1);
475
+ });
476
+ ```
477
+
325
478
  ### Client: Sending a Message
326
479
 
327
480
  The A2AClient makes it easy to communicate with any A2A-compliant agent.
@@ -9,6 +9,10 @@ export interface ServiceUrls {
9
9
  agents?: string;
10
10
  events?: string;
11
11
  llmtrack?: string;
12
+ /** Base URL for the PS LLM API. Used in local mode to route LLM calls in-process.
13
+ * e.g. 'https://dev.lionis.ai' — the /api/v1/llm path is appended automatically.
14
+ * Defaults to the agents service base URL when not specified. */
15
+ llm?: string;
12
16
  }
13
17
  export declare function sleep(ms: number): Promise<void>;
14
18
  /**
@@ -63,6 +67,8 @@ export declare class PSAgent implements AgentExecutor {
63
67
  private readonly log?;
64
68
  private serviceUrls?;
65
69
  private cancelledTasks;
70
+ private localAgent?;
71
+ private localEventLog;
66
72
  cancelTask: (taskId: string) => Promise<void>;
67
73
  /**
68
74
  * create a new PSAgent with the given config
@@ -232,6 +238,35 @@ export declare class PSAgent implements AgentExecutor {
232
238
  * @returns
233
239
  */
234
240
  execute(requestContext: RequestContext, eventBus: ExecutionEventBus): Promise<void>;
241
+ /**
242
+ * Translate an agent-core AgentEvent into a LocalAgentEvent.
243
+ * Returns undefined for events that don't need to be surfaced.
244
+ */
245
+ private translateAgentEvent;
246
+ /**
247
+ * Wrap a PSAgentTool as an agent-core AgentTool.
248
+ * The JSON Schema requestBody is passed as parameters directly—agent-core's
249
+ * validateToolArguments handles plain JSON Schema without TypeBox conversion.
250
+ */
251
+ private bridgePSToolToAgentTool;
252
+ /**
253
+ * Build a single-text user AgentMessage from a start() input object.
254
+ */
255
+ private buildUserMessage;
256
+ /**
257
+ * Convert history entries (remote format) to AgentMessage[] for agent-core.
258
+ */
259
+ private buildHistoryMessages;
260
+ /**
261
+ * Local start() path — runs agent-core in-process.
262
+ * Non-blocking: kicks off the loop and returns a synthetic correlation ID immediately.
263
+ */
264
+ private startLocal;
265
+ /**
266
+ * Local execute() path — A2A AgentExecutor using agent-core streaming.
267
+ * Publishes TaskStatusUpdateEvents to the eventBus as events arrive, without polling.
268
+ */
269
+ private executeLocal;
235
270
  private getHostIPAddress;
236
271
  /**
237
272
  * Port for A2A express server