programgarden-core 1.18.0__tar.gz → 1.19.0__tar.gz

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.
Files changed (84) hide show
  1. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/PKG-INFO +1 -1
  2. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/ai.py +5 -0
  3. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/display.py +14 -4
  4. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/infra.py +6 -1
  5. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/pyproject.toml +1 -1
  6. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/README.md +0 -0
  7. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/__init__.py +0 -0
  8. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/bases/__init__.py +0 -0
  9. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/bases/client.py +0 -0
  10. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/bases/components.py +0 -0
  11. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/bases/listener.py +0 -0
  12. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/bases/mixins.py +0 -0
  13. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/bases/products.py +0 -0
  14. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/bases/sql.py +0 -0
  15. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/bases/storage.py +0 -0
  16. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/code_node.py +0 -0
  17. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/exceptions.py +0 -0
  18. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/expression/__init__.py +0 -0
  19. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/expression/evaluator.py +0 -0
  20. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/i18n/__init__.py +0 -0
  21. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/i18n/locales/en.json +0 -0
  22. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/i18n/locales/ko.json +0 -0
  23. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/i18n/translator.py +0 -0
  24. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/korea_alias.py +0 -0
  25. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/models/__init__.py +0 -0
  26. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/models/connection_rule.py +0 -0
  27. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/models/credential.py +0 -0
  28. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/models/edge.py +0 -0
  29. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/models/event.py +0 -0
  30. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/models/exchange.py +0 -0
  31. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/models/field_binding.py +0 -0
  32. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/models/job.py +0 -0
  33. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/models/order_diagnostics.py +0 -0
  34. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/models/plugin_resource.py +0 -0
  35. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/models/resilience.py +0 -0
  36. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/models/resource.py +0 -0
  37. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/models/validation.py +0 -0
  38. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/models/workflow.py +0 -0
  39. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/__init__.py +0 -0
  40. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/account_futures.py +0 -0
  41. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/account_korea_stock.py +0 -0
  42. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/account_stock.py +0 -0
  43. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/backtest.py +0 -0
  44. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/backtest_futures.py +0 -0
  45. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/backtest_korea_stock.py +0 -0
  46. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/backtest_stock.py +0 -0
  47. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/base.py +0 -0
  48. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/broker.py +0 -0
  49. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/calculation.py +0 -0
  50. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/code.py +0 -0
  51. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/condition.py +0 -0
  52. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/data.py +0 -0
  53. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/data_futures.py +0 -0
  54. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/data_korea_stock.py +0 -0
  55. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/data_stock.py +0 -0
  56. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/event.py +0 -0
  57. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/fundamental_korea_stock.py +0 -0
  58. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/fundamental_stock.py +0 -0
  59. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/market_external.py +0 -0
  60. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/market_status.py +0 -0
  61. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/open_orders_futures.py +0 -0
  62. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/open_orders_korea_stock.py +0 -0
  63. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/open_orders_stock.py +0 -0
  64. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/order.py +0 -0
  65. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/portfolio.py +0 -0
  66. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/realtime_futures.py +0 -0
  67. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/realtime_korea_stock.py +0 -0
  68. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/realtime_stock.py +0 -0
  69. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/risk.py +0 -0
  70. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/symbol.py +0 -0
  71. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/symbol_futures.py +0 -0
  72. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/symbol_korea_stock.py +0 -0
  73. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/symbol_stock.py +0 -0
  74. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/nodes/trigger.py +0 -0
  75. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/presets/__init__.py +0 -0
  76. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/presets/news_analyst.json +0 -0
  77. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/presets/risk_manager.json +0 -0
  78. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/presets/strategist.json +0 -0
  79. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/presets/technical_analyst.json +0 -0
  80. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/registry/__init__.py +0 -0
  81. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/registry/credential_registry.py +0 -0
  82. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/registry/node_registry.py +0 -0
  83. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/registry/plugin_registry.py +0 -0
  84. {programgarden_core-1.18.0 → programgarden_core-1.19.0}/programgarden_core/retry_executor.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: programgarden-core
3
- Version: 1.18.0
3
+ Version: 1.19.0
4
4
  Summary: ProgramGarden Core - 노드 기반 DSL 핵심 타입 정의
5
5
  License-Expression: AGPL-3.0-or-later
6
6
  Author: 프로그램동산
@@ -360,6 +360,11 @@ class AIAgentNode(BaseNode):
360
360
  "max_total_tokens (default 100,000) caps total token spend per execution cycle",
361
361
  ]
362
362
  _anti_patterns: ClassVar[List[Dict[str, str]]] = [
363
+ {
364
+ "pattern": "Adding an AIAgentNode without connecting an LLMModelNode via an 'ai_model' edge",
365
+ "reason": "AIAgentNode CANNOT run without an LLM — the ai_model edge injects the LLM connection. With no LLMModelNode wired via an ai_model edge, the node fails at runtime (raises). The workflow validator now blocks this with an ERROR at save time.",
366
+ "alternative": "Always add an LLMModelNode and wire it to the AIAgentNode with an ai_model edge: {\"from\": \"<llm_node_id>\", \"to\": \"<agent_id>\", \"type\": \"ai_model\"}. A plain 'main' edge does NOT inject the LLM.",
367
+ },
363
368
  {
364
369
  "pattern": "Connecting a real-time node (RealMarketDataNode) directly to AIAgentNode without ThrottleNode",
365
370
  "reason": "Real-time nodes fire on every tick. Without throttling, AIAgentNode would call the LLM API thousands of times per minute, causing massive cost and rate limit errors. The workflow validator blocks this with an ERROR.",
@@ -10,7 +10,7 @@ ProgramGarden Core - Display Nodes
10
10
  - SummaryDisplayNode: JSON/요약 데이터 표시
11
11
  """
12
12
 
13
- from typing import Optional, List, Literal, Dict, Any, ClassVar, TYPE_CHECKING
13
+ from typing import Optional, List, Literal, Dict, Any, Union, ClassVar, TYPE_CHECKING
14
14
  from pydantic import Field
15
15
 
16
16
  if TYPE_CHECKING:
@@ -304,9 +304,16 @@ class TableDisplayNode(BaseDisplayNode):
304
304
  _updated_at: ClassVar[str] = "2026-05-19"
305
305
  _change_note: ClassVar[Optional[str]] = None
306
306
 
307
- columns: Optional[List[str]] = Field(
307
+ # columns 형태를 모두 받는다(스키마=코드=카탈로그 정합; 렌더러 _normalize_columns):
308
+ # 1) 필드명 문자열 리스트 — ["symbol", "close"]
309
+ # 2) {key, label} 객체 리스트 — [{"key": "close", "label": "종가"}] (현지화 헤더용)
310
+ # 옛 선언은 List[str] 뿐이라 객체형을 코드만 몰래 허용하는 드리프트였다.
311
+ columns: Optional[List[Union[str, Dict[str, Any]]]] = Field(
308
312
  default=None,
309
- description="표시할 컬럼 목록 (미지정시 전체)",
313
+ description=(
314
+ "표시할 컬럼 (미지정시 전체). 필드명 문자열 리스트 [\"symbol\",\"close\"] 또는 "
315
+ "현지화 헤더용 객체 리스트 [{\"key\":\"close\",\"label\":\"종가\"}] 둘 다 허용."
316
+ ),
310
317
  )
311
318
 
312
319
  limit: Optional[int] = Field(
@@ -336,7 +343,10 @@ class TableDisplayNode(BaseDisplayNode):
336
343
  "columns": FieldSchema(
337
344
  name="columns",
338
345
  type=FieldType.ARRAY,
339
- description="표시할 컬럼 목록",
346
+ description=(
347
+ "표시할 컬럼. 필드명 문자열 리스트 [\"symbol\",\"close\"] 또는 "
348
+ "{key,label} 객체 리스트 [{\"key\":\"close\",\"label\":\"종가\"}](현지화 헤더) 허용"
349
+ ),
340
350
  category=FieldCategory.SETTINGS,
341
351
  expression_mode=ExpressionMode.FIXED_ONLY,
342
352
  ui_options={"multiple": True},
@@ -457,6 +457,11 @@ class SplitNode(BaseNode):
457
457
  "reason": "Auto-iterate is implicit and handled by the executor — adding SplitNode duplicates the iteration and doubles the workload.",
458
458
  "alternative": "Bind `{{ item }}` directly on the downstream node and delete SplitNode.",
459
459
  },
460
+ {
461
+ "pattern": "Adding SplitNode without wiring its `array` input to an upstream list producer",
462
+ "reason": "SplitNode with no array source (no WatchlistNode/MarketUniverseNode/AccountNode/ConditionNode feeding a list, and no `array` binding) emits zero items — downstream `{{ nodes.split.item }}` resolves empty and the workflow produces silent empty results.",
463
+ "alternative": "Wire an upstream node that outputs an array into SplitNode, or — for a single known symbol — delete SplitNode and bind that symbol directly on the downstream node.",
464
+ },
460
465
  {
461
466
  "pattern": "parallel=True for order-placement loops",
462
467
  "reason": "Placing orders concurrently without delay_ms will trip LS-Sec TR rate limits and cause spurious cancellations.",
@@ -530,7 +535,7 @@ class SplitNode(BaseNode):
530
535
  },
531
536
  ]
532
537
  _node_guide: ClassVar[Dict[str, Any]] = {
533
- "input_handling": "`array` input typically bound implicitly by the upstream array output. No explicit config needed; SplitNode infers the iteration from the DAG.",
538
+ "input_handling": "`array` input is REQUIRED and MUST have a source: either an incoming edge from an upstream node that outputs an ARRAY (WatchlistNode/MarketUniverseNode → symbols, AccountNode → positions/held_symbols, ConditionNode → values, etc.), or an explicit `array` config binding. SplitNode has NOTHING to split if no upstream produces a list — it emits zero items and every downstream `{{ nodes.split.item }}` silently resolves empty. If you already know a single concrete symbol (e.g. 'AAPL'), do NOT add SplitNode — bind that one symbol directly on the downstream node.",
534
539
  "output_consumption": "Downstream binds `{{ nodes.split.item }}` for the current element, `{{ nodes.split.index }}` for the 0-based position, and `{{ nodes.split.total }}` for the count.",
535
540
  "common_combinations": [
536
541
  "WatchlistNode → SplitNode → OverseasStockFundamentalNode",
@@ -5,7 +5,7 @@ authors = [
5
5
  homepage = "https://programgarden.com"
6
6
  requires-python = ">=3.12"
7
7
  name = "programgarden-core"
8
- version = "1.18.0"
8
+ version = "1.19.0"
9
9
  license = "AGPL-3.0-or-later"
10
10
  description = "ProgramGarden Core - 노드 기반 DSL 핵심 타입 정의"
11
11
  readme = "README.md"