construct-labs-crm-env 0.1.1__py3-none-any.whl → 0.1.3__py3-none-any.whl
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.
- construct_labs_crm_env/__init__.py +7 -2
- construct_labs_crm_env/client.py +65 -554
- construct_labs_crm_env/models.py +1 -2
- construct_labs_crm_env/tools.py +611 -0
- {construct_labs_crm_env-0.1.1.dist-info → construct_labs_crm_env-0.1.3.dist-info}/METADATA +2 -1
- construct_labs_crm_env-0.1.3.dist-info/RECORD +10 -0
- construct_labs_crm_env-0.1.3.dist-info/licenses/LICENSE +56 -0
- construct_labs_crm_env/_vendored/LICENSE.openenv +0 -28
- construct_labs_crm_env/_vendored/__init__.py +0 -14
- construct_labs_crm_env/_vendored/_client.py +0 -216
- construct_labs_crm_env/_vendored/_types.py +0 -82
- construct_labs_crm_env-0.1.1.dist-info/RECORD +0 -13
- construct_labs_crm_env-0.1.1.dist-info/licenses/LICENSE +0 -42
- {construct_labs_crm_env-0.1.1.dist-info → construct_labs_crm_env-0.1.3.dist-info}/WHEEL +0 -0
construct_labs_crm_env/client.py
CHANGED
|
@@ -24,9 +24,10 @@ import json
|
|
|
24
24
|
import os
|
|
25
25
|
from typing import Any, cast
|
|
26
26
|
|
|
27
|
+
from openenv.core import EnvClient
|
|
28
|
+
from openenv.core.client_types import StepResult
|
|
27
29
|
from websockets.sync.client import connect as ws_connect
|
|
28
30
|
|
|
29
|
-
from ._vendored import EnvClient, StepResult
|
|
30
31
|
from .models import (
|
|
31
32
|
CRMActionType,
|
|
32
33
|
CrmAgentAction,
|
|
@@ -34,6 +35,7 @@ from .models import (
|
|
|
34
35
|
CrmAgentState,
|
|
35
36
|
)
|
|
36
37
|
from .protocol import ParsedAction
|
|
38
|
+
from .tools import DEFAULT_TOOLS
|
|
37
39
|
|
|
38
40
|
# Type alias for JSON-serializable dictionaries
|
|
39
41
|
JsonDict = dict[str, Any]
|
|
@@ -104,7 +106,7 @@ class CrmAgentEnv(EnvClient[CrmAgentAction, CrmAgentObservation, CrmAgentState])
|
|
|
104
106
|
raise ValueError(
|
|
105
107
|
"API key is required. Pass api_key parameter or set "
|
|
106
108
|
"CRM_AGENT_API_KEY environment variable. "
|
|
107
|
-
"
|
|
109
|
+
"Contact hello@construct-labs.com to obtain an API key."
|
|
108
110
|
)
|
|
109
111
|
|
|
110
112
|
self._api_key = resolved_api_key
|
|
@@ -161,7 +163,7 @@ class CrmAgentEnv(EnvClient[CrmAgentAction, CrmAgentObservation, CrmAgentState])
|
|
|
161
163
|
if "401" in error_msg or "403" in error_msg or "4001" in error_msg:
|
|
162
164
|
raise ConnectionError(
|
|
163
165
|
"Authentication failed. Please verify your API key. "
|
|
164
|
-
"
|
|
166
|
+
"Contact hello@construct-labs.com if you need assistance."
|
|
165
167
|
) from e
|
|
166
168
|
raise ConnectionError(f"Failed to connect to {self._ws_url}: {e}") from e
|
|
167
169
|
finally:
|
|
@@ -193,12 +195,6 @@ class CrmAgentEnv(EnvClient[CrmAgentAction, CrmAgentObservation, CrmAgentState])
|
|
|
193
195
|
"""Parse server response into CrmAgentState."""
|
|
194
196
|
return CrmAgentState.model_validate(payload)
|
|
195
197
|
|
|
196
|
-
def _reset_payload(self, seed: int | None = None) -> JsonDict:
|
|
197
|
-
"""Create payload for reset request."""
|
|
198
|
-
if seed is not None:
|
|
199
|
-
return {"seed": seed}
|
|
200
|
-
return {}
|
|
201
|
-
|
|
202
198
|
# =========================================================================
|
|
203
199
|
# Extensible Properties - Override these in subclasses
|
|
204
200
|
# =========================================================================
|
|
@@ -269,11 +265,12 @@ IMPORTANT: Output ONLY a tool_call, no other text."""
|
|
|
269
265
|
def tools(self) -> list[JsonDict]:
|
|
270
266
|
"""Tool definitions for the CRM environment.
|
|
271
267
|
|
|
272
|
-
|
|
273
|
-
|
|
268
|
+
Returns tool definitions formatted by `format_tools()`. Override
|
|
269
|
+
`format_tools()` to transform the tool schema for different providers
|
|
270
|
+
(e.g., Anthropic, Google).
|
|
274
271
|
|
|
275
272
|
Returns:
|
|
276
|
-
List of tool definitions
|
|
273
|
+
List of tool definitions (OpenAI format by default).
|
|
277
274
|
|
|
278
275
|
Example:
|
|
279
276
|
>>> class ReadOnlyAgent(CrmAgentEnv):
|
|
@@ -284,7 +281,34 @@ IMPORTANT: Output ONLY a tool_call, no other text."""
|
|
|
284
281
|
... return [t for t in self._default_tools()
|
|
285
282
|
... if any(op in t['function']['name'] for op in read_ops)]
|
|
286
283
|
"""
|
|
287
|
-
return self._default_tools()
|
|
284
|
+
return self.format_tools(self._default_tools())
|
|
285
|
+
|
|
286
|
+
def format_tools(self, tools: list[JsonDict]) -> list[JsonDict]:
|
|
287
|
+
"""Format tool definitions for the target LLM provider.
|
|
288
|
+
|
|
289
|
+
Override this method to transform tool schemas for different providers.
|
|
290
|
+
The default implementation returns OpenAI-compatible format unchanged.
|
|
291
|
+
|
|
292
|
+
Args:
|
|
293
|
+
tools: List of tool definitions in OpenAI format.
|
|
294
|
+
|
|
295
|
+
Returns:
|
|
296
|
+
Formatted tool definitions for your target provider.
|
|
297
|
+
|
|
298
|
+
Example (Anthropic format):
|
|
299
|
+
>>> class AnthropicCrmAgent(CrmAgentEnv):
|
|
300
|
+
... def format_tools(self, tools):
|
|
301
|
+
... # Convert OpenAI format to Anthropic format
|
|
302
|
+
... return [
|
|
303
|
+
... {
|
|
304
|
+
... "name": t["function"]["name"],
|
|
305
|
+
... "description": t["function"]["description"],
|
|
306
|
+
... "input_schema": t["function"]["parameters"],
|
|
307
|
+
... }
|
|
308
|
+
... for t in tools
|
|
309
|
+
... ]
|
|
310
|
+
"""
|
|
311
|
+
return tools
|
|
288
312
|
|
|
289
313
|
def _default_tools(self) -> list[JsonDict]:
|
|
290
314
|
"""Return the default tool definitions.
|
|
@@ -292,548 +316,9 @@ IMPORTANT: Output ONLY a tool_call, no other text."""
|
|
|
292
316
|
Subclasses can call this to get all default tools and filter/extend them.
|
|
293
317
|
|
|
294
318
|
Returns:
|
|
295
|
-
Complete list of CRM tool definitions.
|
|
319
|
+
Complete list of CRM tool definitions in OpenAI format.
|
|
296
320
|
"""
|
|
297
|
-
return
|
|
298
|
-
# =================================================================
|
|
299
|
-
# Company Tools
|
|
300
|
-
# =================================================================
|
|
301
|
-
{
|
|
302
|
-
"type": "function",
|
|
303
|
-
"function": {
|
|
304
|
-
"name": "list_companies",
|
|
305
|
-
"description": "List all companies in the CRM",
|
|
306
|
-
"parameters": {
|
|
307
|
-
"type": "object",
|
|
308
|
-
"properties": {
|
|
309
|
-
"limit": {
|
|
310
|
-
"type": "integer",
|
|
311
|
-
"default": 60,
|
|
312
|
-
"description": "Maximum number of companies to return (max 200)",
|
|
313
|
-
},
|
|
314
|
-
"starting_after": {
|
|
315
|
-
"type": "string",
|
|
316
|
-
"description": "Cursor for pagination - returns objects after this ID",
|
|
317
|
-
},
|
|
318
|
-
"ending_before": {
|
|
319
|
-
"type": "string",
|
|
320
|
-
"description": "Cursor for pagination - returns objects before this ID",
|
|
321
|
-
},
|
|
322
|
-
"order_by": {
|
|
323
|
-
"type": "string",
|
|
324
|
-
"description": "Order by: field_name[ASC|DESC]",
|
|
325
|
-
},
|
|
326
|
-
"filter": {
|
|
327
|
-
"type": "string",
|
|
328
|
-
"description": "Filter: field[eq|gt|lt|contains]:value",
|
|
329
|
-
},
|
|
330
|
-
"depth": {
|
|
331
|
-
"type": "integer",
|
|
332
|
-
"default": 1,
|
|
333
|
-
"description": "Relation depth: 0=primary only, 1=include relations",
|
|
334
|
-
},
|
|
335
|
-
},
|
|
336
|
-
"required": [],
|
|
337
|
-
},
|
|
338
|
-
},
|
|
339
|
-
},
|
|
340
|
-
{
|
|
341
|
-
"type": "function",
|
|
342
|
-
"function": {
|
|
343
|
-
"name": "get_company",
|
|
344
|
-
"description": "Get details of a specific company",
|
|
345
|
-
"parameters": {
|
|
346
|
-
"type": "object",
|
|
347
|
-
"properties": {
|
|
348
|
-
"record_id": {
|
|
349
|
-
"type": "string",
|
|
350
|
-
"description": "ID of the company to retrieve",
|
|
351
|
-
},
|
|
352
|
-
"depth": {
|
|
353
|
-
"type": "integer",
|
|
354
|
-
"default": 1,
|
|
355
|
-
"description": "Relation depth: 0=primary only, 1=include relations",
|
|
356
|
-
},
|
|
357
|
-
},
|
|
358
|
-
"required": ["record_id"],
|
|
359
|
-
},
|
|
360
|
-
},
|
|
361
|
-
},
|
|
362
|
-
{
|
|
363
|
-
"type": "function",
|
|
364
|
-
"function": {
|
|
365
|
-
"name": "create_company",
|
|
366
|
-
"description": "Create a new company in the CRM",
|
|
367
|
-
"parameters": {
|
|
368
|
-
"type": "object",
|
|
369
|
-
"properties": {
|
|
370
|
-
"company_name": {
|
|
371
|
-
"type": "string",
|
|
372
|
-
"description": "Name of the company",
|
|
373
|
-
},
|
|
374
|
-
"company_domain": {
|
|
375
|
-
"type": "string",
|
|
376
|
-
"description": "Domain/website of the company",
|
|
377
|
-
},
|
|
378
|
-
"company_address": {
|
|
379
|
-
"type": "string",
|
|
380
|
-
"description": "Address of the company",
|
|
381
|
-
},
|
|
382
|
-
"company_employees": {
|
|
383
|
-
"type": "integer",
|
|
384
|
-
"description": "Number of employees",
|
|
385
|
-
},
|
|
386
|
-
},
|
|
387
|
-
"required": ["company_name"],
|
|
388
|
-
},
|
|
389
|
-
},
|
|
390
|
-
},
|
|
391
|
-
{
|
|
392
|
-
"type": "function",
|
|
393
|
-
"function": {
|
|
394
|
-
"name": "update_company",
|
|
395
|
-
"description": "Update an existing company",
|
|
396
|
-
"parameters": {
|
|
397
|
-
"type": "object",
|
|
398
|
-
"properties": {
|
|
399
|
-
"record_id": {
|
|
400
|
-
"type": "string",
|
|
401
|
-
"description": "ID of the company to update",
|
|
402
|
-
},
|
|
403
|
-
"company_name": {"type": "string"},
|
|
404
|
-
"company_domain": {"type": "string"},
|
|
405
|
-
"company_address": {"type": "string"},
|
|
406
|
-
"company_employees": {"type": "integer"},
|
|
407
|
-
},
|
|
408
|
-
"required": ["record_id"],
|
|
409
|
-
},
|
|
410
|
-
},
|
|
411
|
-
},
|
|
412
|
-
{
|
|
413
|
-
"type": "function",
|
|
414
|
-
"function": {
|
|
415
|
-
"name": "delete_company",
|
|
416
|
-
"description": "Delete a company from the CRM",
|
|
417
|
-
"parameters": {
|
|
418
|
-
"type": "object",
|
|
419
|
-
"properties": {
|
|
420
|
-
"record_id": {
|
|
421
|
-
"type": "string",
|
|
422
|
-
"description": "ID of the company to delete",
|
|
423
|
-
},
|
|
424
|
-
},
|
|
425
|
-
"required": ["record_id"],
|
|
426
|
-
},
|
|
427
|
-
},
|
|
428
|
-
},
|
|
429
|
-
# =================================================================
|
|
430
|
-
# Person/Contact Tools
|
|
431
|
-
# =================================================================
|
|
432
|
-
{
|
|
433
|
-
"type": "function",
|
|
434
|
-
"function": {
|
|
435
|
-
"name": "list_people",
|
|
436
|
-
"description": "List all contacts/people in the CRM",
|
|
437
|
-
"parameters": {
|
|
438
|
-
"type": "object",
|
|
439
|
-
"properties": {
|
|
440
|
-
"limit": {
|
|
441
|
-
"type": "integer",
|
|
442
|
-
"default": 60,
|
|
443
|
-
"description": "Maximum number of contacts to return (max 200)",
|
|
444
|
-
},
|
|
445
|
-
"starting_after": {"type": "string"},
|
|
446
|
-
"ending_before": {"type": "string"},
|
|
447
|
-
"order_by": {"type": "string"},
|
|
448
|
-
"filter": {"type": "string"},
|
|
449
|
-
"depth": {"type": "integer", "default": 1},
|
|
450
|
-
},
|
|
451
|
-
"required": [],
|
|
452
|
-
},
|
|
453
|
-
},
|
|
454
|
-
},
|
|
455
|
-
{
|
|
456
|
-
"type": "function",
|
|
457
|
-
"function": {
|
|
458
|
-
"name": "get_person",
|
|
459
|
-
"description": "Get details of a specific contact",
|
|
460
|
-
"parameters": {
|
|
461
|
-
"type": "object",
|
|
462
|
-
"properties": {
|
|
463
|
-
"record_id": {
|
|
464
|
-
"type": "string",
|
|
465
|
-
"description": "ID of the contact to retrieve",
|
|
466
|
-
},
|
|
467
|
-
"depth": {"type": "integer", "default": 1},
|
|
468
|
-
},
|
|
469
|
-
"required": ["record_id"],
|
|
470
|
-
},
|
|
471
|
-
},
|
|
472
|
-
},
|
|
473
|
-
{
|
|
474
|
-
"type": "function",
|
|
475
|
-
"function": {
|
|
476
|
-
"name": "create_person",
|
|
477
|
-
"description": "Create a new contact/person in the CRM",
|
|
478
|
-
"parameters": {
|
|
479
|
-
"type": "object",
|
|
480
|
-
"properties": {
|
|
481
|
-
"person_first_name": {
|
|
482
|
-
"type": "string",
|
|
483
|
-
"description": "First name",
|
|
484
|
-
},
|
|
485
|
-
"person_last_name": {
|
|
486
|
-
"type": "string",
|
|
487
|
-
"description": "Last name",
|
|
488
|
-
},
|
|
489
|
-
"person_email": {
|
|
490
|
-
"type": "string",
|
|
491
|
-
"description": "Email address",
|
|
492
|
-
},
|
|
493
|
-
"person_phone": {
|
|
494
|
-
"type": "string",
|
|
495
|
-
"description": "Phone number",
|
|
496
|
-
},
|
|
497
|
-
"person_company_id": {
|
|
498
|
-
"type": "string",
|
|
499
|
-
"description": "ID of associated company",
|
|
500
|
-
},
|
|
501
|
-
"person_job_title": {
|
|
502
|
-
"type": "string",
|
|
503
|
-
"description": "Job title",
|
|
504
|
-
},
|
|
505
|
-
},
|
|
506
|
-
"required": ["person_first_name", "person_last_name"],
|
|
507
|
-
},
|
|
508
|
-
},
|
|
509
|
-
},
|
|
510
|
-
{
|
|
511
|
-
"type": "function",
|
|
512
|
-
"function": {
|
|
513
|
-
"name": "update_person",
|
|
514
|
-
"description": "Update an existing contact",
|
|
515
|
-
"parameters": {
|
|
516
|
-
"type": "object",
|
|
517
|
-
"properties": {
|
|
518
|
-
"record_id": {
|
|
519
|
-
"type": "string",
|
|
520
|
-
"description": "ID of the contact to update",
|
|
521
|
-
},
|
|
522
|
-
"person_first_name": {"type": "string"},
|
|
523
|
-
"person_last_name": {"type": "string"},
|
|
524
|
-
"person_email": {"type": "string"},
|
|
525
|
-
"person_phone": {"type": "string"},
|
|
526
|
-
"person_job_title": {"type": "string"},
|
|
527
|
-
},
|
|
528
|
-
"required": ["record_id"],
|
|
529
|
-
},
|
|
530
|
-
},
|
|
531
|
-
},
|
|
532
|
-
{
|
|
533
|
-
"type": "function",
|
|
534
|
-
"function": {
|
|
535
|
-
"name": "delete_person",
|
|
536
|
-
"description": "Delete a contact from the CRM",
|
|
537
|
-
"parameters": {
|
|
538
|
-
"type": "object",
|
|
539
|
-
"properties": {
|
|
540
|
-
"record_id": {
|
|
541
|
-
"type": "string",
|
|
542
|
-
"description": "ID of the contact to delete",
|
|
543
|
-
},
|
|
544
|
-
},
|
|
545
|
-
"required": ["record_id"],
|
|
546
|
-
},
|
|
547
|
-
},
|
|
548
|
-
},
|
|
549
|
-
# =================================================================
|
|
550
|
-
# Opportunity Tools
|
|
551
|
-
# =================================================================
|
|
552
|
-
{
|
|
553
|
-
"type": "function",
|
|
554
|
-
"function": {
|
|
555
|
-
"name": "list_opportunities",
|
|
556
|
-
"description": "List all opportunities/deals in the CRM",
|
|
557
|
-
"parameters": {
|
|
558
|
-
"type": "object",
|
|
559
|
-
"properties": {
|
|
560
|
-
"limit": {
|
|
561
|
-
"type": "integer",
|
|
562
|
-
"default": 60,
|
|
563
|
-
"description": "Maximum number to return (max 200)",
|
|
564
|
-
},
|
|
565
|
-
"starting_after": {"type": "string"},
|
|
566
|
-
"ending_before": {"type": "string"},
|
|
567
|
-
"order_by": {"type": "string"},
|
|
568
|
-
"filter": {"type": "string"},
|
|
569
|
-
"depth": {"type": "integer", "default": 1},
|
|
570
|
-
},
|
|
571
|
-
"required": [],
|
|
572
|
-
},
|
|
573
|
-
},
|
|
574
|
-
},
|
|
575
|
-
{
|
|
576
|
-
"type": "function",
|
|
577
|
-
"function": {
|
|
578
|
-
"name": "get_opportunity",
|
|
579
|
-
"description": "Get details of a specific opportunity",
|
|
580
|
-
"parameters": {
|
|
581
|
-
"type": "object",
|
|
582
|
-
"properties": {
|
|
583
|
-
"record_id": {
|
|
584
|
-
"type": "string",
|
|
585
|
-
"description": "ID of the opportunity",
|
|
586
|
-
},
|
|
587
|
-
"depth": {"type": "integer", "default": 1},
|
|
588
|
-
},
|
|
589
|
-
"required": ["record_id"],
|
|
590
|
-
},
|
|
591
|
-
},
|
|
592
|
-
},
|
|
593
|
-
{
|
|
594
|
-
"type": "function",
|
|
595
|
-
"function": {
|
|
596
|
-
"name": "create_opportunity",
|
|
597
|
-
"description": "Create a new opportunity/deal",
|
|
598
|
-
"parameters": {
|
|
599
|
-
"type": "object",
|
|
600
|
-
"properties": {
|
|
601
|
-
"opportunity_name": {
|
|
602
|
-
"type": "string",
|
|
603
|
-
"description": "Name of the opportunity",
|
|
604
|
-
},
|
|
605
|
-
"opportunity_amount": {
|
|
606
|
-
"type": "number",
|
|
607
|
-
"description": "Deal value",
|
|
608
|
-
},
|
|
609
|
-
"opportunity_stage": {
|
|
610
|
-
"type": "string",
|
|
611
|
-
"enum": ["NEW", "MEETING", "PROPOSAL", "WON", "LOST"],
|
|
612
|
-
"description": "Sales stage",
|
|
613
|
-
},
|
|
614
|
-
"opportunity_close_date": {
|
|
615
|
-
"type": "string",
|
|
616
|
-
"description": "Expected close date (ISO format)",
|
|
617
|
-
},
|
|
618
|
-
"opportunity_company_id": {
|
|
619
|
-
"type": "string",
|
|
620
|
-
"description": "Associated company ID",
|
|
621
|
-
},
|
|
622
|
-
"opportunity_person_id": {
|
|
623
|
-
"type": "string",
|
|
624
|
-
"description": "Point of contact ID",
|
|
625
|
-
},
|
|
626
|
-
},
|
|
627
|
-
"required": ["opportunity_name"],
|
|
628
|
-
},
|
|
629
|
-
},
|
|
630
|
-
},
|
|
631
|
-
{
|
|
632
|
-
"type": "function",
|
|
633
|
-
"function": {
|
|
634
|
-
"name": "update_opportunity",
|
|
635
|
-
"description": "Update an existing opportunity",
|
|
636
|
-
"parameters": {
|
|
637
|
-
"type": "object",
|
|
638
|
-
"properties": {
|
|
639
|
-
"record_id": {
|
|
640
|
-
"type": "string",
|
|
641
|
-
"description": "ID of the opportunity to update",
|
|
642
|
-
},
|
|
643
|
-
"opportunity_name": {"type": "string"},
|
|
644
|
-
"opportunity_amount": {"type": "number"},
|
|
645
|
-
"opportunity_stage": {
|
|
646
|
-
"type": "string",
|
|
647
|
-
"enum": ["NEW", "MEETING", "PROPOSAL", "WON", "LOST"],
|
|
648
|
-
},
|
|
649
|
-
"opportunity_close_date": {"type": "string"},
|
|
650
|
-
},
|
|
651
|
-
"required": ["record_id"],
|
|
652
|
-
},
|
|
653
|
-
},
|
|
654
|
-
},
|
|
655
|
-
{
|
|
656
|
-
"type": "function",
|
|
657
|
-
"function": {
|
|
658
|
-
"name": "delete_opportunity",
|
|
659
|
-
"description": "Delete an opportunity",
|
|
660
|
-
"parameters": {
|
|
661
|
-
"type": "object",
|
|
662
|
-
"properties": {
|
|
663
|
-
"record_id": {
|
|
664
|
-
"type": "string",
|
|
665
|
-
"description": "ID of the opportunity to delete",
|
|
666
|
-
},
|
|
667
|
-
},
|
|
668
|
-
"required": ["record_id"],
|
|
669
|
-
},
|
|
670
|
-
},
|
|
671
|
-
},
|
|
672
|
-
# =================================================================
|
|
673
|
-
# Note Tools
|
|
674
|
-
# =================================================================
|
|
675
|
-
{
|
|
676
|
-
"type": "function",
|
|
677
|
-
"function": {
|
|
678
|
-
"name": "list_notes",
|
|
679
|
-
"description": "List all notes in the CRM",
|
|
680
|
-
"parameters": {
|
|
681
|
-
"type": "object",
|
|
682
|
-
"properties": {
|
|
683
|
-
"limit": {
|
|
684
|
-
"type": "integer",
|
|
685
|
-
"default": 10,
|
|
686
|
-
"description": "Maximum number of notes to return",
|
|
687
|
-
},
|
|
688
|
-
},
|
|
689
|
-
"required": [],
|
|
690
|
-
},
|
|
691
|
-
},
|
|
692
|
-
},
|
|
693
|
-
{
|
|
694
|
-
"type": "function",
|
|
695
|
-
"function": {
|
|
696
|
-
"name": "create_note",
|
|
697
|
-
"description": "Create a note attached to a record",
|
|
698
|
-
"parameters": {
|
|
699
|
-
"type": "object",
|
|
700
|
-
"properties": {
|
|
701
|
-
"note_body": {
|
|
702
|
-
"type": "string",
|
|
703
|
-
"description": "Content of the note",
|
|
704
|
-
},
|
|
705
|
-
"note_target_id": {
|
|
706
|
-
"type": "string",
|
|
707
|
-
"description": "ID of record to attach note to",
|
|
708
|
-
},
|
|
709
|
-
"note_target_type": {
|
|
710
|
-
"type": "string",
|
|
711
|
-
"enum": ["company", "person", "opportunity"],
|
|
712
|
-
"description": "Type of record",
|
|
713
|
-
},
|
|
714
|
-
},
|
|
715
|
-
"required": ["note_body"],
|
|
716
|
-
},
|
|
717
|
-
},
|
|
718
|
-
},
|
|
719
|
-
# =================================================================
|
|
720
|
-
# Task Tools
|
|
721
|
-
# =================================================================
|
|
722
|
-
{
|
|
723
|
-
"type": "function",
|
|
724
|
-
"function": {
|
|
725
|
-
"name": "list_tasks",
|
|
726
|
-
"description": "List all tasks in the CRM",
|
|
727
|
-
"parameters": {
|
|
728
|
-
"type": "object",
|
|
729
|
-
"properties": {
|
|
730
|
-
"limit": {
|
|
731
|
-
"type": "integer",
|
|
732
|
-
"default": 10,
|
|
733
|
-
"description": "Maximum number of tasks to return",
|
|
734
|
-
},
|
|
735
|
-
},
|
|
736
|
-
"required": [],
|
|
737
|
-
},
|
|
738
|
-
},
|
|
739
|
-
},
|
|
740
|
-
{
|
|
741
|
-
"type": "function",
|
|
742
|
-
"function": {
|
|
743
|
-
"name": "create_task",
|
|
744
|
-
"description": "Create a task, optionally linked to a record",
|
|
745
|
-
"parameters": {
|
|
746
|
-
"type": "object",
|
|
747
|
-
"properties": {
|
|
748
|
-
"task_title": {
|
|
749
|
-
"type": "string",
|
|
750
|
-
"description": "Title of the task",
|
|
751
|
-
},
|
|
752
|
-
"task_body": {
|
|
753
|
-
"type": "string",
|
|
754
|
-
"description": "Description",
|
|
755
|
-
},
|
|
756
|
-
"task_due_date": {
|
|
757
|
-
"type": "string",
|
|
758
|
-
"description": "Due date (ISO format)",
|
|
759
|
-
},
|
|
760
|
-
"task_status": {
|
|
761
|
-
"type": "string",
|
|
762
|
-
"enum": ["TODO", "IN_PROGRESS", "DONE"],
|
|
763
|
-
"description": "Status",
|
|
764
|
-
},
|
|
765
|
-
"task_target_id": {
|
|
766
|
-
"type": "string",
|
|
767
|
-
"description": "ID of record to link task to",
|
|
768
|
-
},
|
|
769
|
-
"task_target_type": {
|
|
770
|
-
"type": "string",
|
|
771
|
-
"enum": ["company", "person", "opportunity"],
|
|
772
|
-
"description": "Type of record",
|
|
773
|
-
},
|
|
774
|
-
},
|
|
775
|
-
"required": ["task_title"],
|
|
776
|
-
},
|
|
777
|
-
},
|
|
778
|
-
},
|
|
779
|
-
{
|
|
780
|
-
"type": "function",
|
|
781
|
-
"function": {
|
|
782
|
-
"name": "update_task",
|
|
783
|
-
"description": "Update an existing task",
|
|
784
|
-
"parameters": {
|
|
785
|
-
"type": "object",
|
|
786
|
-
"properties": {
|
|
787
|
-
"record_id": {
|
|
788
|
-
"type": "string",
|
|
789
|
-
"description": "ID of the task to update",
|
|
790
|
-
},
|
|
791
|
-
"task_title": {"type": "string"},
|
|
792
|
-
"task_body": {"type": "string"},
|
|
793
|
-
"task_due_date": {"type": "string"},
|
|
794
|
-
},
|
|
795
|
-
"required": ["record_id"],
|
|
796
|
-
},
|
|
797
|
-
},
|
|
798
|
-
},
|
|
799
|
-
{
|
|
800
|
-
"type": "function",
|
|
801
|
-
"function": {
|
|
802
|
-
"name": "complete_task",
|
|
803
|
-
"description": "Mark a task as complete",
|
|
804
|
-
"parameters": {
|
|
805
|
-
"type": "object",
|
|
806
|
-
"properties": {
|
|
807
|
-
"record_id": {
|
|
808
|
-
"type": "string",
|
|
809
|
-
"description": "ID of the task to complete",
|
|
810
|
-
},
|
|
811
|
-
},
|
|
812
|
-
"required": ["record_id"],
|
|
813
|
-
},
|
|
814
|
-
},
|
|
815
|
-
},
|
|
816
|
-
# =================================================================
|
|
817
|
-
# Submit Answer Tool
|
|
818
|
-
# =================================================================
|
|
819
|
-
{
|
|
820
|
-
"type": "function",
|
|
821
|
-
"function": {
|
|
822
|
-
"name": "submit_answer",
|
|
823
|
-
"description": "Submit final answer and end the session",
|
|
824
|
-
"parameters": {
|
|
825
|
-
"type": "object",
|
|
826
|
-
"properties": {
|
|
827
|
-
"answer": {
|
|
828
|
-
"type": "string",
|
|
829
|
-
"description": "The final answer based on CRM data",
|
|
830
|
-
},
|
|
831
|
-
},
|
|
832
|
-
"required": ["answer"],
|
|
833
|
-
},
|
|
834
|
-
},
|
|
835
|
-
},
|
|
836
|
-
]
|
|
321
|
+
return list(DEFAULT_TOOLS)
|
|
837
322
|
|
|
838
323
|
# =========================================================================
|
|
839
324
|
# Tool Parsing and Observation Formatting
|
|
@@ -966,6 +451,32 @@ IMPORTANT: Output ONLY a tool_call, no other text."""
|
|
|
966
451
|
if field in arguments and arguments[field] is not None:
|
|
967
452
|
action_kwargs[field] = arguments[field]
|
|
968
453
|
|
|
454
|
+
# Convert generic note_target_id/type to specific fields
|
|
455
|
+
# Tool schema uses: note_target_id + note_target_type
|
|
456
|
+
# Server expects: note_target_person_id, note_target_company_id, etc.
|
|
457
|
+
note_target_id = action_kwargs.pop("note_target_id", None)
|
|
458
|
+
note_target_type = action_kwargs.pop("note_target_type", None)
|
|
459
|
+
if note_target_id and note_target_type:
|
|
460
|
+
target_type = str(note_target_type).lower()
|
|
461
|
+
if target_type == "person":
|
|
462
|
+
action_kwargs["note_target_person_id"] = note_target_id
|
|
463
|
+
elif target_type == "company":
|
|
464
|
+
action_kwargs["note_target_company_id"] = note_target_id
|
|
465
|
+
elif target_type == "opportunity":
|
|
466
|
+
action_kwargs["note_target_opportunity_id"] = note_target_id
|
|
467
|
+
|
|
468
|
+
# Same conversion for tasks
|
|
469
|
+
task_target_id = action_kwargs.pop("task_target_id", None)
|
|
470
|
+
task_target_type = action_kwargs.pop("task_target_type", None)
|
|
471
|
+
if task_target_id and task_target_type:
|
|
472
|
+
target_type = str(task_target_type).lower()
|
|
473
|
+
if target_type == "person":
|
|
474
|
+
action_kwargs["task_target_person_id"] = task_target_id
|
|
475
|
+
elif target_type == "company":
|
|
476
|
+
action_kwargs["task_target_company_id"] = task_target_id
|
|
477
|
+
elif target_type == "opportunity":
|
|
478
|
+
action_kwargs["task_target_opportunity_id"] = task_target_id
|
|
479
|
+
|
|
969
480
|
try:
|
|
970
481
|
action = CrmAgentAction(**action_kwargs)
|
|
971
482
|
return ParsedAction(action=action, is_valid=True)
|