ironshell 1.5.1__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.
ironshell/__init__.py ADDED
@@ -0,0 +1,682 @@
1
+ """
2
+ IronShell Python SDK
3
+
4
+ AI-powered typed shell with agent orchestration capabilities.
5
+
6
+ Modules:
7
+ - workflows: Workflow patterns (MapReduce, Saga, Pipeline, Fan-Out)
8
+ - metrics: Observability (Prometheus metrics, tracing, health checks)
9
+ - distributed: Distributed agents (service registry, leader election, routing)
10
+ - langchain: LangChain integration tools
11
+ """
12
+
13
+ from __future__ import annotations
14
+
15
+ from dataclasses import dataclass, field
16
+ from enum import Enum
17
+ from importlib.metadata import PackageNotFoundError
18
+ from importlib.metadata import version as _distribution_version
19
+ from typing import Any, Callable, Dict, List, Optional, Union
20
+ import json
21
+ import re
22
+ import subprocess
23
+ import sys
24
+ import os
25
+
26
+
27
+ def _read_version() -> str:
28
+ """The SDK version, from the installed distribution or the source tree.
29
+
30
+ pyproject.toml is the one source. An installed distribution reports it
31
+ through importlib.metadata; a bare source checkout reads it from the
32
+ pyproject.toml two levels above this package.
33
+ """
34
+ try:
35
+ return _distribution_version("ironshell")
36
+ except PackageNotFoundError:
37
+ pass
38
+ pyproject = os.path.join(os.path.dirname(__file__), os.pardir, os.pardir, "pyproject.toml")
39
+ try:
40
+ with open(pyproject, encoding="utf-8") as f:
41
+ match = re.search(r'^version\s*=\s*"([^"]+)"', f.read(), re.MULTILINE)
42
+ except OSError:
43
+ match = None
44
+ return match.group(1) if match else "0+unknown"
45
+
46
+
47
+ __version__ = _read_version()
48
+ __all__ = [
49
+ "IronShellRuntime",
50
+ "Agent",
51
+ "AgentConfig",
52
+ "AgentResult",
53
+ "Swarm",
54
+ "SwarmConfig",
55
+ "SwarmResult",
56
+ "A2UIEvent",
57
+ "NotificationLevel",
58
+ "PipelineBuilder",
59
+ "evaluate",
60
+ "pipeline",
61
+ ]
62
+
63
+
64
+ class NotificationLevel(Enum):
65
+ """A2UI notification levels"""
66
+ INFO = "info"
67
+ SUCCESS = "success"
68
+ WARNING = "warning"
69
+ ERROR = "error"
70
+
71
+
72
+ @dataclass
73
+ class A2UIEvent:
74
+ """Event from A2UI protocol"""
75
+ id: str
76
+ timestamp: str
77
+ priority: str
78
+ event_type: str
79
+ data: Dict[str, Any]
80
+
81
+
82
+ @dataclass
83
+ class AgentConfig:
84
+ """Configuration for an agent"""
85
+ name: str
86
+ model: str = "openai:gpt-4o-mini"
87
+ tools: List[str] = field(default_factory=list)
88
+ max_steps: int = 10
89
+ dry_run: bool = False
90
+
91
+
92
+ @dataclass
93
+ class AgentResult:
94
+ """Result from agent execution"""
95
+ success: bool
96
+ result: Any
97
+ trace: List[Dict[str, Any]]
98
+ steps_taken: int
99
+
100
+
101
+ @dataclass
102
+ class SwarmConfig:
103
+ """Configuration for a swarm"""
104
+ agents: List[Agent]
105
+ policy: str = "round_robin"
106
+ max_iterations: int = 10
107
+
108
+
109
+ @dataclass
110
+ class SwarmResult:
111
+ """Result from swarm execution"""
112
+ success: bool
113
+ result: Any
114
+ blackboard: Dict[str, Any]
115
+ iterations: int
116
+
117
+
118
+ class Agent:
119
+ """AI Agent with tool execution capabilities"""
120
+
121
+ def __init__(
122
+ self,
123
+ name: str,
124
+ model: str = "openai:gpt-4o-mini",
125
+ tools: Optional[List[str]] = None,
126
+ max_steps: int = 10,
127
+ runtime: Optional[IronShellRuntime] = None,
128
+ system_prompt: Optional[str] = None,
129
+ ):
130
+ if system_prompt is not None:
131
+ # The agent builtin's config record has no system prompt key (its
132
+ # keys are goal, tools, max_steps, dry_run), and nothing else in the
133
+ # shell takes one, so the prompt could never reach the model.
134
+ raise ValueError(
135
+ "Agent system_prompt is not supported: the agent builtin has no "
136
+ "system prompt option, so the prompt cannot reach the model; "
137
+ "remove the argument and put the instructions in the goal"
138
+ )
139
+ self.name = name
140
+ self.model = model
141
+ self.tools = tools or []
142
+ self.max_steps = max_steps
143
+ self._runtime = runtime
144
+ self.trace: List[Dict[str, Any]] = []
145
+
146
+ async def run(self, goal: str) -> AgentResult:
147
+ """Execute the agent with a goal.
148
+
149
+ Raises ValueError, before anything runs, for a model other than the
150
+ default or a max_steps outside 1..=1000 (see `_build_agent_code`).
151
+ """
152
+ # Build the call first, so an unsupported option is refused without
153
+ # locating or starting the ish binary.
154
+ code = _build_agent_code(goal, self.model, self.tools, self.max_steps)
155
+
156
+ if self._runtime is None:
157
+ self._runtime = IronShellRuntime()
158
+
159
+ result = self._runtime.eval(code)
160
+
161
+ if isinstance(result, dict):
162
+ return AgentResult(
163
+ success=result.get("success", False),
164
+ result=result.get("result"),
165
+ trace=result.get("trace", []),
166
+ steps_taken=result.get("steps", 0),
167
+ )
168
+ # The builtin returns its final answer as a String and reports no
169
+ # trace or step count. A returned value means the run did not fail.
170
+ return AgentResult(success=True, result=result, trace=[], steps_taken=0)
171
+
172
+ def __repr__(self) -> str:
173
+ return f"Agent(name={self.name!r}, model={self.model!r}, tools={self.tools})"
174
+
175
+
176
+ class Swarm:
177
+ """Multi-agent swarm with coordination"""
178
+
179
+ def __init__(
180
+ self,
181
+ agents: List[Agent],
182
+ policy: str = "round_robin",
183
+ max_iterations: int = 10,
184
+ runtime: Optional[IronShellRuntime] = None,
185
+ ):
186
+ self.agents = agents
187
+ self.policy = policy
188
+ self.max_iterations = max_iterations
189
+ self._runtime = runtime
190
+
191
+ async def run(self, goal: str) -> SwarmResult:
192
+ """Execute the swarm with a goal.
193
+
194
+ Raises ValueError, before anything runs, for any option the `swarm`
195
+ builtin cannot honour (see `_build_swarm_code`).
196
+ """
197
+ # Build the call first, so an unsupported option is refused without
198
+ # locating or starting the ish binary.
199
+ code = _build_swarm_code(self.agents, goal, self.policy, self.max_iterations)
200
+
201
+ if self._runtime is None:
202
+ self._runtime = IronShellRuntime()
203
+
204
+ result = self._runtime.eval(code)
205
+
206
+ if isinstance(result, dict):
207
+ return SwarmResult(
208
+ success=result.get("success", False),
209
+ result=result.get("result"),
210
+ blackboard=result.get("blackboard", {}),
211
+ iterations=result.get("iterations", 0),
212
+ )
213
+ # The builtin returns the combined answer as a String and reports no
214
+ # blackboard or iteration count. A returned value means the run did
215
+ # not fail, so success is True and the other fields are empty.
216
+ return SwarmResult(success=True, result=result, blackboard={}, iterations=0)
217
+
218
+
219
+ # Defaults that the SDK's Agent and Swarm classes start from. The `swarm`
220
+ # builtin has no model, policy or per-agent step option, so a non-default value
221
+ # for any of them is refused rather than silently dropped.
222
+ _DEFAULT_AGENT_MODEL = "openai:gpt-4o-mini"
223
+ _DEFAULT_AGENT_MAX_STEPS = 10
224
+ _DEFAULT_SWARM_POLICY = "round_robin"
225
+ # The builtin's upper bound on max_steps (MAX_AGENT_STEPS in src/builtins.rs).
226
+ _SWARM_MAX_STEPS = 1000
227
+
228
+
229
+ def _ironshell_string(value: str) -> str:
230
+ """Render a Python str as an IronShell double-quoted string literal.
231
+
232
+ The lexer unescapes backslash, double quote, n, r and t, so those are
233
+ escaped here. Any other backslash sequence is not decoded (a backslash
234
+ followed by u is read as a plain u), so no unicode escape is ever emitted:
235
+ non-ASCII text is written as itself, which the lexer reads as characters.
236
+
237
+ Three inputs are refused rather than emitted wrong: "${" (the lexer has no
238
+ escape for it, and the evaluator interpolates ${...} in any string literal),
239
+ a control character other than tab, newline or carriage return (the lexer
240
+ has no escape for it, and NUL cannot be passed in a command line), and a
241
+ lone surrogate (it has no UTF-8 encoding).
242
+ """
243
+ if not isinstance(value, str):
244
+ raise TypeError(f"expected a str for an IronShell string, got {type(value).__name__}")
245
+ if "${" in value:
246
+ raise ValueError(
247
+ "text containing '${' cannot be passed to IronShell: string literals "
248
+ "interpolate ${...}, and the language has no escape for it"
249
+ )
250
+ for ch in value:
251
+ code = ord(ch)
252
+ if code < 0x20 and ch not in "\t\n\r":
253
+ raise ValueError(
254
+ f"control character U+{code:04X} cannot be passed to IronShell: "
255
+ "the lexer has no escape for it"
256
+ )
257
+ if 0xD800 <= code <= 0xDFFF:
258
+ raise ValueError(
259
+ f"lone surrogate U+{code:04X} cannot be passed to IronShell: "
260
+ "it has no UTF-8 encoding"
261
+ )
262
+ escaped = (
263
+ value.replace("\\", "\\\\")
264
+ .replace('"', '\\"')
265
+ .replace("\n", "\\n")
266
+ .replace("\r", "\\r")
267
+ .replace("\t", "\\t")
268
+ )
269
+ return f'"{escaped}"'
270
+
271
+
272
+ _IDENTIFIER = re.compile(r"[A-Za-z_][A-Za-z0-9_]*\Z")
273
+
274
+
275
+ def _ironshell_value(value: Any) -> str:
276
+ """Render a Python value as an IronShell literal.
277
+
278
+ Strings go through _ironshell_string. Lists become arrays, and dicts become
279
+ records whose keys must be identifiers, since the parser reads record keys
280
+ as bare names. None, True and False become null, true and false.
281
+ """
282
+ if value is None:
283
+ return "null"
284
+ if isinstance(value, bool):
285
+ return "true" if value else "false"
286
+ if isinstance(value, str):
287
+ return _ironshell_string(value)
288
+ if isinstance(value, int):
289
+ return str(value)
290
+ if isinstance(value, float):
291
+ if value != value or value in (float("inf"), float("-inf")):
292
+ raise ValueError(f"{value!r} has no IronShell literal")
293
+ return repr(value)
294
+ if isinstance(value, (list, tuple)):
295
+ return "[" + ", ".join(_ironshell_value(v) for v in value) + "]"
296
+ if isinstance(value, dict):
297
+ fields = []
298
+ for key, item in value.items():
299
+ if not isinstance(key, str) or not _IDENTIFIER.match(key):
300
+ raise ValueError(
301
+ f"record key {key!r} is not an identifier; IronShell record keys are bare names"
302
+ )
303
+ fields.append(f"{key}: {_ironshell_value(item)}")
304
+ return "{" + ", ".join(fields) + "}"
305
+ raise TypeError(f"{type(value).__name__} has no IronShell literal")
306
+
307
+
308
+ def _check_steps(value: int, owner: str) -> int:
309
+ """Return value if it is a legal step count for the builtin, else raise ValueError."""
310
+ if not isinstance(value, int) or isinstance(value, bool) or not 1 <= value <= _SWARM_MAX_STEPS:
311
+ raise ValueError(
312
+ f"{owner} must be an int in 1..={_SWARM_MAX_STEPS} "
313
+ f"(the builtin's max_steps), got {value!r}"
314
+ )
315
+ return value
316
+
317
+
318
+ def _build_agent_code(goal: str, model: str, tools: List[str], max_steps: int) -> str:
319
+ """Build the IronShell call that runs one agent.
320
+
321
+ Produces the record form of the builtin, `agent({goal, tools, max_steps})`.
322
+ Raises ValueError for a model other than the default, since the builtin has
323
+ no model option, and for a max_steps outside 1..=1000.
324
+ """
325
+ if model != _DEFAULT_AGENT_MODEL:
326
+ raise ValueError(
327
+ f"Agent model {model!r} is not supported: the agent builtin has no model "
328
+ f"option; leave the model at {_DEFAULT_AGENT_MODEL!r}"
329
+ )
330
+ steps = _check_steps(max_steps, "max_steps")
331
+ tools_str = ", ".join(_ironshell_string(t) for t in tools)
332
+ return (
333
+ f"agent({{goal: {_ironshell_string(goal)}, tools: [{tools_str}], "
334
+ f"max_steps: {steps}}})"
335
+ )
336
+
337
+
338
+ def _build_swarm_code(
339
+ agents: List[Agent],
340
+ goal: str,
341
+ policy: str,
342
+ max_iterations: int,
343
+ ) -> str:
344
+ """Build the IronShell call that runs a swarm.
345
+
346
+ Produces the record form of the builtin, `swarm({goal, tools, max_steps})`.
347
+ `tools` is the union of the agents' tools, in first-seen order. Raises
348
+ ValueError for an option the builtin cannot honour: a policy other than
349
+ round_robin, a per-agent model or max_steps other than the SDK defaults,
350
+ or a max_iterations outside 1..=1000.
351
+ """
352
+ if policy != _DEFAULT_SWARM_POLICY:
353
+ raise ValueError(
354
+ f"Swarm policy {policy!r} is not supported: the swarm builtin has no "
355
+ f"policy option and always runs {_DEFAULT_SWARM_POLICY!r}"
356
+ )
357
+ if (
358
+ not isinstance(max_iterations, int)
359
+ or isinstance(max_iterations, bool)
360
+ or not 1 <= max_iterations <= _SWARM_MAX_STEPS
361
+ ):
362
+ raise ValueError(
363
+ f"max_iterations must be an int in 1..={_SWARM_MAX_STEPS} "
364
+ f"(the swarm builtin's max_steps), got {max_iterations!r}"
365
+ )
366
+
367
+ tools: List[str] = []
368
+ for agent in agents:
369
+ if agent.model != _DEFAULT_AGENT_MODEL:
370
+ raise ValueError(
371
+ f"Agent {agent.name!r} sets model {agent.model!r}, but the swarm builtin "
372
+ "has no per-agent model option; leave the model at its default"
373
+ )
374
+ if agent.max_steps != _DEFAULT_AGENT_MAX_STEPS:
375
+ raise ValueError(
376
+ f"Agent {agent.name!r} sets max_steps={agent.max_steps!r}, but the swarm "
377
+ "builtin has no per-agent step limit; use max_iterations on the swarm"
378
+ )
379
+ for tool in agent.tools:
380
+ if tool not in tools:
381
+ tools.append(tool)
382
+
383
+ tools_str = ", ".join(_ironshell_string(t) for t in tools)
384
+ return (
385
+ f"swarm({{goal: {_ironshell_string(goal)}, tools: [{tools_str}], "
386
+ f"max_steps: {max_iterations}}})"
387
+ )
388
+
389
+
390
+ class IronShellRuntime:
391
+ """Main runtime for IronShell execution"""
392
+
393
+ def __init__(self, ish_path: Optional[str] = None):
394
+ """
395
+ Initialize the IronShell runtime.
396
+
397
+ Args:
398
+ ish_path: Path to the ish binary. If None, searches PATH.
399
+ """
400
+ self._ish_path = ish_path or self._find_ish()
401
+ self._event_listeners: List[Callable[[A2UIEvent], None]] = []
402
+
403
+ def _find_ish(self) -> str:
404
+ """Find the ish binary in PATH or common locations"""
405
+ # Check PATH
406
+ for path in os.environ.get("PATH", "").split(os.pathsep):
407
+ ae = os.path.join(path, "ish.exe" if sys.platform == "win32" else "ish")
408
+ if os.path.isfile(ae):
409
+ return ae
410
+
411
+ # Check common locations
412
+ common_paths = [
413
+ "/usr/local/bin/ae",
414
+ "/usr/bin/ae",
415
+ os.path.expanduser("~/.cargo/bin/ae"),
416
+ os.path.expanduser("~/bin/ae"),
417
+ ]
418
+ if sys.platform == "win32":
419
+ common_paths.extend([
420
+ r"C:\Program Files\IronShell\ish.exe",
421
+ os.path.expanduser(r"~\.cargo\bin\ish.exe"),
422
+ ])
423
+
424
+ for path in common_paths:
425
+ if os.path.isfile(path):
426
+ return path
427
+
428
+ raise RuntimeError(
429
+ "Could not find 'ish' binary. Please install IronShell or "
430
+ "provide the path explicitly via ish_path parameter."
431
+ )
432
+
433
+ def eval(self, code: str) -> Any:
434
+ """
435
+ Evaluate IronShell code and return the result.
436
+
437
+ Args:
438
+ code: IronShell code to evaluate
439
+
440
+ Returns:
441
+ Parsed result (Python object)
442
+ """
443
+ # `-c/--command`, not `-e`, and `--deterministic` for canonical JSON.
444
+ # The previous flags (`-e ... --json`) are not accepted by the binary:
445
+ # clap rejected `-e` outright, so every call raised RuntimeError. The
446
+ # SDK's core entry point could never have worked against a released
447
+ # build.
448
+ result = subprocess.run(
449
+ [self._ish_path, "-c", code, "--deterministic"],
450
+ capture_output=True,
451
+ text=True,
452
+ timeout=60,
453
+ )
454
+
455
+ if result.returncode != 0:
456
+ raise RuntimeError(f"IronShell error: {result.stderr}")
457
+
458
+ try:
459
+ return json.loads(result.stdout)
460
+ except json.JSONDecodeError:
461
+ return result.stdout.strip()
462
+
463
+ def eval_file(self, path: str) -> Any:
464
+ """
465
+ Evaluate an IronShell file.
466
+
467
+ Args:
468
+ path: Path to .ish file
469
+
470
+ Returns:
471
+ Result of evaluation
472
+ """
473
+ result = subprocess.run(
474
+ [self._ish_path, path, "--deterministic"],
475
+ capture_output=True,
476
+ text=True,
477
+ timeout=300,
478
+ )
479
+
480
+ if result.returncode != 0:
481
+ raise RuntimeError(f"IronShell error: {result.stderr}")
482
+
483
+ try:
484
+ return json.loads(result.stdout)
485
+ except json.JSONDecodeError:
486
+ return result.stdout.strip()
487
+
488
+ def create_agent(
489
+ self,
490
+ name: str,
491
+ model: str = "openai:gpt-4o-mini",
492
+ tools: Optional[List[str]] = None,
493
+ max_steps: int = 10,
494
+ ) -> Agent:
495
+ """
496
+ Create an AI agent.
497
+
498
+ Args:
499
+ name: Agent identifier
500
+ model: Must be the default "openai:gpt-4o-mini". The agent builtin
501
+ has no model option, so any other value raises ValueError when
502
+ the agent runs.
503
+ tools: List of tool names the agent can use
504
+ max_steps: Maximum reasoning steps
505
+
506
+ Returns:
507
+ Agent instance
508
+ """
509
+ return Agent(
510
+ name=name,
511
+ model=model,
512
+ tools=tools or [],
513
+ max_steps=max_steps,
514
+ runtime=self,
515
+ )
516
+
517
+ def create_swarm(
518
+ self,
519
+ agents: List[Agent],
520
+ policy: str = "round_robin",
521
+ max_iterations: int = 10,
522
+ ) -> Swarm:
523
+ """
524
+ Create a multi-agent swarm.
525
+
526
+ Args:
527
+ agents: List of agents in the swarm
528
+ policy: Must be "round_robin". The swarm builtin has no policy
529
+ option, so any other value raises ValueError when the swarm runs.
530
+ max_iterations: Maximum coordination iterations, 1 to 1000
531
+
532
+ Returns:
533
+ Swarm instance
534
+ """
535
+ return Swarm(
536
+ agents=agents,
537
+ policy=policy,
538
+ max_iterations=max_iterations,
539
+ runtime=self,
540
+ )
541
+
542
+ async def run_swarm(
543
+ self,
544
+ agents: List[Agent],
545
+ goal: str,
546
+ policy: str = "round_robin",
547
+ max_iterations: int = 10,
548
+ ) -> SwarmResult:
549
+ """
550
+ Run a multi-agent swarm with a goal.
551
+
552
+ Args:
553
+ agents: List of agents
554
+ goal: Goal for the swarm
555
+ policy: Must be "round_robin" (see create_swarm)
556
+ max_iterations: Maximum iterations, 1 to 1000
557
+
558
+ Returns:
559
+ SwarmResult
560
+ """
561
+ swarm = self.create_swarm(agents, policy, max_iterations)
562
+ return await swarm.run(goal)
563
+
564
+ def subscribe_a2ui(
565
+ self,
566
+ callback: Callable[[A2UIEvent], None],
567
+ ) -> Callable[[], None]:
568
+ """
569
+ Subscribe to A2UI events.
570
+
571
+ Args:
572
+ callback: Function called for each event
573
+
574
+ Returns:
575
+ Unsubscribe function
576
+ """
577
+ self._event_listeners.append(callback)
578
+
579
+ def unsubscribe():
580
+ self._event_listeners.remove(callback)
581
+
582
+ return unsubscribe
583
+
584
+ def _emit_event(self, event: A2UIEvent) -> None:
585
+ """Emit an event to all listeners"""
586
+ for listener in self._event_listeners:
587
+ try:
588
+ listener(event)
589
+ except Exception as e:
590
+ print(f"A2UI event listener error: {e}", file=sys.stderr)
591
+
592
+
593
+ def evaluate(code: str) -> Any:
594
+ """
595
+ Convenience function to evaluate IronShell code.
596
+
597
+ Args:
598
+ code: IronShell code to evaluate
599
+
600
+ Returns:
601
+ Result
602
+ """
603
+ runtime = IronShellRuntime()
604
+ return runtime.eval(code)
605
+
606
+
607
+ class PipelineBuilder:
608
+ """Fluent API for building pipelines"""
609
+
610
+ def __init__(self, data: Any):
611
+ self._data = data
612
+ self._ops: List[str] = []
613
+
614
+ def map(self, fn: str) -> PipelineBuilder:
615
+ self._ops.append(f"map({fn})")
616
+ return self
617
+
618
+ def filter(self, fn: str) -> PipelineBuilder:
619
+ # The shell calls this `where`; there is no `filter` builtin.
620
+ self._ops.append(f"where({fn})")
621
+ return self
622
+
623
+ def reduce(self, fn: str, initial: Any) -> PipelineBuilder:
624
+ self._ops.append(f"reduce({fn}, {_ironshell_value(initial)})")
625
+ return self
626
+
627
+ def sort(self, fn: Optional[str] = None) -> PipelineBuilder:
628
+ # `fn` is a key function, `fn(x) => key`: `sort` takes no argument, and
629
+ # `sort_by` orders by the key it returns.
630
+ self._ops.append(f"sort_by({fn})" if fn else "sort()")
631
+ return self
632
+
633
+ def reverse(self) -> PipelineBuilder:
634
+ self._ops.append("reverse()")
635
+ return self
636
+
637
+ def flatten(self) -> PipelineBuilder:
638
+ self._ops.append("flatten()")
639
+ return self
640
+
641
+ def unique(self) -> PipelineBuilder:
642
+ self._ops.append("unique()")
643
+ return self
644
+
645
+ def take(self, n: int) -> PipelineBuilder:
646
+ self._ops.append(f"slice(0, {n})")
647
+ return self
648
+
649
+ def skip(self, n: int) -> PipelineBuilder:
650
+ self._ops.append(f"slice({n})")
651
+ return self
652
+
653
+ def to_code(self) -> str:
654
+ """Get the pipeline as IronShell code"""
655
+ return f"{_ironshell_value(self._data)} | {' | '.join(self._ops)}"
656
+
657
+ def run(self, runtime: Optional[IronShellRuntime] = None) -> Any:
658
+ """Execute the pipeline"""
659
+ rt = runtime or IronShellRuntime()
660
+ return rt.eval(self.to_code())
661
+
662
+
663
+ def pipeline(data: Any) -> PipelineBuilder:
664
+ """
665
+ Create a pipeline builder for fluent data processing.
666
+
667
+ Args:
668
+ data: Initial data
669
+
670
+ Returns:
671
+ PipelineBuilder for chaining operations
672
+
673
+ Example:
674
+ result = (
675
+ pipeline([1, 2, 3, 4, 5])
676
+ .map("fn(x) => x * 2")
677
+ .filter("fn(x) => x > 4")
678
+ .run()
679
+ )
680
+ # [6, 8, 10]
681
+ """
682
+ return PipelineBuilder(data)