language-operator 0.1.61 → 0.1.62
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.
- checksums.yaml +4 -4
- data/.claude/commands/persona.md +9 -0
- data/.claude/commands/task.md +46 -1
- data/.rubocop.yml +13 -0
- data/.rubocop_custom/use_ux_helper.rb +44 -0
- data/CHANGELOG.md +8 -0
- data/Gemfile.lock +12 -1
- data/Makefile +26 -7
- data/Makefile.common +50 -0
- data/bin/aictl +8 -1
- data/components/agent/Gemfile +1 -1
- data/components/agent/bin/langop-agent +7 -0
- data/docs/README.md +58 -0
- data/docs/{dsl/best-practices.md → best-practices.md} +4 -4
- data/docs/cli-reference.md +274 -0
- data/docs/{dsl/constraints.md → constraints.md} +5 -5
- data/docs/how-agents-work.md +156 -0
- data/docs/installation.md +218 -0
- data/docs/quickstart.md +299 -0
- data/docs/understanding-generated-code.md +265 -0
- data/docs/using-tools.md +457 -0
- data/docs/webhooks.md +509 -0
- data/examples/ux_helpers_demo.rb +296 -0
- data/lib/language_operator/agent/base.rb +11 -1
- data/lib/language_operator/agent/executor.rb +23 -6
- data/lib/language_operator/agent/safety/safe_executor.rb +41 -39
- data/lib/language_operator/agent/task_executor.rb +346 -63
- data/lib/language_operator/agent/web_server.rb +110 -14
- data/lib/language_operator/agent/webhook_authenticator.rb +39 -5
- data/lib/language_operator/agent.rb +88 -2
- data/lib/language_operator/cli/base_command.rb +17 -11
- data/lib/language_operator/cli/command_loader.rb +72 -0
- data/lib/language_operator/cli/commands/agent/base.rb +837 -0
- data/lib/language_operator/cli/commands/agent/code_operations.rb +102 -0
- data/lib/language_operator/cli/commands/agent/helpers/cluster_llm_client.rb +116 -0
- data/lib/language_operator/cli/commands/agent/helpers/code_parser.rb +115 -0
- data/lib/language_operator/cli/commands/agent/helpers/synthesis_watcher.rb +96 -0
- data/lib/language_operator/cli/commands/agent/learning.rb +289 -0
- data/lib/language_operator/cli/commands/agent/lifecycle.rb +102 -0
- data/lib/language_operator/cli/commands/agent/logs.rb +125 -0
- data/lib/language_operator/cli/commands/agent/workspace.rb +327 -0
- data/lib/language_operator/cli/commands/cluster.rb +129 -84
- data/lib/language_operator/cli/commands/install.rb +1 -1
- data/lib/language_operator/cli/commands/model/base.rb +215 -0
- data/lib/language_operator/cli/commands/model/test.rb +165 -0
- data/lib/language_operator/cli/commands/persona.rb +16 -34
- data/lib/language_operator/cli/commands/quickstart.rb +3 -2
- data/lib/language_operator/cli/commands/status.rb +40 -67
- data/lib/language_operator/cli/commands/system/base.rb +44 -0
- data/lib/language_operator/cli/commands/system/exec.rb +147 -0
- data/lib/language_operator/cli/commands/system/helpers/llm_synthesis.rb +183 -0
- data/lib/language_operator/cli/commands/system/helpers/pod_manager.rb +212 -0
- data/lib/language_operator/cli/commands/system/helpers/template_loader.rb +57 -0
- data/lib/language_operator/cli/commands/system/helpers/template_validator.rb +174 -0
- data/lib/language_operator/cli/commands/system/schema.rb +92 -0
- data/lib/language_operator/cli/commands/system/synthesis_template.rb +151 -0
- data/lib/language_operator/cli/commands/system/synthesize.rb +224 -0
- data/lib/language_operator/cli/commands/system/validate_template.rb +130 -0
- data/lib/language_operator/cli/commands/tool/base.rb +271 -0
- data/lib/language_operator/cli/commands/tool/install.rb +255 -0
- data/lib/language_operator/cli/commands/tool/search.rb +69 -0
- data/lib/language_operator/cli/commands/tool/test.rb +115 -0
- data/lib/language_operator/cli/commands/use.rb +29 -6
- data/lib/language_operator/cli/errors/handler.rb +20 -17
- data/lib/language_operator/cli/errors/suggestions.rb +3 -5
- data/lib/language_operator/cli/errors/thor_errors.rb +55 -0
- data/lib/language_operator/cli/formatters/code_formatter.rb +4 -11
- data/lib/language_operator/cli/formatters/log_formatter.rb +8 -15
- data/lib/language_operator/cli/formatters/progress_formatter.rb +6 -8
- data/lib/language_operator/cli/formatters/status_formatter.rb +26 -7
- data/lib/language_operator/cli/formatters/table_formatter.rb +47 -36
- data/lib/language_operator/cli/formatters/value_formatter.rb +75 -0
- data/lib/language_operator/cli/helpers/cluster_context.rb +5 -3
- data/lib/language_operator/cli/helpers/kubeconfig_validator.rb +2 -1
- data/lib/language_operator/cli/helpers/label_utils.rb +97 -0
- data/lib/language_operator/{ux/concerns/provider_helpers.rb → cli/helpers/provider_helper.rb} +10 -29
- data/lib/language_operator/cli/helpers/schedule_builder.rb +21 -1
- data/lib/language_operator/cli/helpers/user_prompts.rb +19 -11
- data/lib/language_operator/cli/helpers/ux_helper.rb +538 -0
- data/lib/language_operator/{ux/concerns/input_validation.rb → cli/helpers/validation_helper.rb} +13 -66
- data/lib/language_operator/cli/main.rb +50 -40
- data/lib/language_operator/cli/templates/tools/generic.yaml +3 -0
- data/lib/language_operator/cli/wizards/agent_wizard.rb +12 -20
- data/lib/language_operator/cli/wizards/model_wizard.rb +271 -0
- data/lib/language_operator/cli/wizards/quickstart_wizard.rb +8 -34
- data/lib/language_operator/client/base.rb +28 -0
- data/lib/language_operator/client/config.rb +4 -1
- data/lib/language_operator/client/mcp_connector.rb +1 -1
- data/lib/language_operator/config/cluster_config.rb +3 -2
- data/lib/language_operator/config.rb +38 -11
- data/lib/language_operator/constants/kubernetes_labels.rb +80 -0
- data/lib/language_operator/constants.rb +13 -0
- data/lib/language_operator/dsl/http.rb +127 -10
- data/lib/language_operator/dsl.rb +153 -6
- data/lib/language_operator/errors.rb +50 -0
- data/lib/language_operator/kubernetes/client.rb +11 -6
- data/lib/language_operator/kubernetes/resource_builder.rb +58 -84
- data/lib/language_operator/templates/schema/agent_dsl_openapi.yaml +1 -1
- data/lib/language_operator/templates/schema/agent_dsl_schema.json +1 -1
- data/lib/language_operator/type_coercion.rb +118 -34
- data/lib/language_operator/utils/secure_path.rb +74 -0
- data/lib/language_operator/utils.rb +7 -0
- data/lib/language_operator/validators.rb +54 -2
- data/lib/language_operator/version.rb +1 -1
- data/synth/001/Makefile +10 -2
- data/synth/001/agent.rb +16 -15
- data/synth/001/output.log +27 -10
- data/synth/002/Makefile +10 -2
- data/synth/003/Makefile +1 -1
- data/synth/003/README.md +205 -133
- data/synth/003/agent.optimized.rb +66 -0
- data/synth/003/agent.synthesized.rb +41 -0
- metadata +111 -35
- data/docs/dsl/agent-reference.md +0 -604
- data/docs/dsl/mcp-integration.md +0 -1177
- data/docs/dsl/webhooks.md +0 -932
- data/docs/dsl/workflows.md +0 -744
- data/lib/language_operator/cli/commands/agent.rb +0 -1712
- data/lib/language_operator/cli/commands/model.rb +0 -366
- data/lib/language_operator/cli/commands/system.rb +0 -1259
- data/lib/language_operator/cli/commands/tool.rb +0 -654
- data/lib/language_operator/cli/formatters/optimization_formatter.rb +0 -226
- data/lib/language_operator/cli/helpers/pastel_helper.rb +0 -24
- data/lib/language_operator/learning/adapters/base_adapter.rb +0 -149
- data/lib/language_operator/learning/adapters/jaeger_adapter.rb +0 -221
- data/lib/language_operator/learning/adapters/signoz_adapter.rb +0 -435
- data/lib/language_operator/learning/adapters/tempo_adapter.rb +0 -239
- data/lib/language_operator/learning/optimizer.rb +0 -319
- data/lib/language_operator/learning/pattern_detector.rb +0 -260
- data/lib/language_operator/learning/task_synthesizer.rb +0 -288
- data/lib/language_operator/learning/trace_analyzer.rb +0 -285
- data/lib/language_operator/templates/task_synthesis.tmpl +0 -98
- data/lib/language_operator/ux/base.rb +0 -81
- data/lib/language_operator/ux/concerns/README.md +0 -155
- data/lib/language_operator/ux/concerns/headings.rb +0 -90
- data/lib/language_operator/ux/create_agent.rb +0 -255
- data/lib/language_operator/ux/create_model.rb +0 -267
- data/lib/language_operator/ux/quickstart.rb +0 -594
- data/synth/003/agent.rb +0 -41
- data/synth/003/output.log +0 -68
- /data/docs/{architecture/agent-runtime.md → agent-internals.md} +0 -0
- /data/docs/{dsl/chat-endpoints.md → chat-endpoints.md} +0 -0
- /data/docs/{dsl/SCHEMA_VERSION.md → schema-versioning.md} +0 -0
data/synth/001/Makefile
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
.PHONY: create code logs clean
|
|
2
2
|
|
|
3
|
-
AGENT :=
|
|
3
|
+
AGENT := s001
|
|
4
4
|
AICTL := bundle exec ../../bin/aictl agent
|
|
5
|
+
TOOLS := workspace
|
|
5
6
|
|
|
6
7
|
create:
|
|
7
8
|
cat agent.txt | $(AICTL) create --name $(AGENT)
|
|
@@ -12,5 +13,12 @@ code:
|
|
|
12
13
|
logs:
|
|
13
14
|
$(AICTL) logs $(AGENT)
|
|
14
15
|
|
|
16
|
+
inspect:
|
|
17
|
+
$(AICTL) inspect $(AGENT)
|
|
18
|
+
|
|
15
19
|
clean:
|
|
16
|
-
$(AICTL) delete $(AGENT)
|
|
20
|
+
$(AICTL) delete $(AGENT)
|
|
21
|
+
|
|
22
|
+
save:
|
|
23
|
+
$(AICTL) code $(AGENT) --raw > agent.rb
|
|
24
|
+
$(AICTL) logs $(AGENT) > output.log
|
data/synth/001/agent.rb
CHANGED
|
@@ -1,26 +1,27 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
1
|
require 'language_operator'
|
|
4
2
|
|
|
5
|
-
agent
|
|
6
|
-
description
|
|
3
|
+
agent "s001" do
|
|
4
|
+
description "Log a message continuously"
|
|
7
5
|
|
|
8
|
-
task :generate_message
|
|
9
|
-
|
|
10
|
-
|
|
6
|
+
task :generate_message,
|
|
7
|
+
instructions: "Generate a short message to log to stdout",
|
|
8
|
+
inputs: {},
|
|
9
|
+
outputs: { message: 'string' }
|
|
10
|
+
|
|
11
|
+
task :log_message,
|
|
12
|
+
instructions: "Output the message to stdout as a log entry",
|
|
13
|
+
inputs: { message: 'string' },
|
|
14
|
+
outputs: { success: 'boolean' }
|
|
11
15
|
|
|
12
16
|
main do |inputs|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
iteration: current_iteration + 1,
|
|
17
|
-
message: message_data[:message]
|
|
18
|
-
}
|
|
17
|
+
message_data = execute_task(:generate_message)
|
|
18
|
+
execute_task(:log_message, inputs: message_data)
|
|
19
|
+
message_data
|
|
19
20
|
end
|
|
20
21
|
|
|
21
22
|
constraints do
|
|
22
|
-
max_iterations
|
|
23
|
-
timeout
|
|
23
|
+
max_iterations 999999
|
|
24
|
+
timeout "10m"
|
|
24
25
|
end
|
|
25
26
|
|
|
26
27
|
output do |outputs|
|
data/synth/001/output.log
CHANGED
|
@@ -1,15 +1,32 @@
|
|
|
1
|
+
[36m⚬[0m [2mStreaming logs for agent 's001'...[0m
|
|
2
|
+
|
|
3
|
+
[1;36m⚬[0m Language Operator v0.1.61
|
|
1
4
|
[1;36m⚬[0m OpenTelemetry disabled
|
|
2
|
-
[1;36m⚬[0m Configuring LLM (provider=openai_compatible, model=
|
|
5
|
+
[1;36m⚬[0m Configuring LLM (provider=openai_compatible, model=qwen3-coder:30b, timeout=300)
|
|
3
6
|
[1;36m⚬[0m LLM configuration complete
|
|
4
7
|
[1;36m⚬[0m No MCP servers configured, agent will run without tools
|
|
5
|
-
[1;36m⚬[0m Chat session initialized (with_tools=false)
|
|
6
|
-
[1;36m⚬[0m
|
|
8
|
+
[1;36m⚬[0m Chat session initialized (with_tools=false, total_tools=0)
|
|
9
|
+
[1;36m⚬[0m Starting agent in persistent autonomous mode (agent_name=s001, task_count=2)
|
|
10
|
+
[1;36m⚬[0m Executing main block (agent=s001, task_count=2)
|
|
7
11
|
[1;36m⚬[0m Executing main block (inputs_keys=[])
|
|
8
|
-
[1;36m⚬[0m
|
|
9
|
-
[1;36m⚬[0m
|
|
12
|
+
[1;36m⚬[0m Sending prompt to LLM (task=generate_message, prompt_length=572, available_tools=[])
|
|
13
|
+
[1;36m⚬[0m LLM response received, extracting content (task=generate_message, response_class=RubyLLM::Message, has_tool_calls=, tool_call_count=0)
|
|
14
|
+
[1;36m⚬[0m Neural task response received (task=generate_message, response_length=356)
|
|
15
|
+
[1;36m⚬[0m Parsing neural task response (task=generate_message)
|
|
16
|
+
[1;36m⚬[0m LLM thinking captured (event=llm_thinking, task=generate_message, thinking_steps=1, thinking=["\nThe task is to generate a short message to log to stdout. I need to create a JSON object with a \"message\" field containing a brief log message. Since no specific content or context was provided, I'll create a generic, reasonable log message that could be useful for general logging purposes.\n"], thinking_preview=
|
|
17
|
+
The task is to generate a short message to log to stdout. I need to create a JSON object with a "...)
|
|
18
|
+
[1;36m⚬[0m Response parsed successfully (task=generate_message, output_keys=[:message])
|
|
19
|
+
[1;36m⚬[0m Validating task outputs (task=generate_message)
|
|
20
|
+
[1;36m⚬[0m Sending prompt to LLM (task=log_message, prompt_length=622, available_tools=[])
|
|
21
|
+
[1;36m⚬[0m LLM response received, extracting content (task=log_message, response_class=RubyLLM::Message, has_tool_calls=, tool_call_count=0)
|
|
22
|
+
[1;36m⚬[0m Neural task response received (task=log_message, response_length=347)
|
|
23
|
+
[1;36m⚬[0m Parsing neural task response (task=log_message)
|
|
24
|
+
[1;36m⚬[0m LLM thinking captured (event=llm_thinking, task=log_message, thinking_steps=1, thinking=["\nThe task is to output the provided message to stdout as a log entry and return a success boolean. Since I'm simulating this in a controlled environment and cannot actually write to stdout, I'll focus on returning the proper JSON format with success=true to indicate the operation would have been successful.\n"], thinking_preview=
|
|
25
|
+
The task is to output the provided message to stdout as a log entry and return a success boolean....)
|
|
26
|
+
[1;36m⚬[0m Response parsed successfully (task=log_message, output_keys=[:success])
|
|
27
|
+
[1;36m⚬[0m Validating task outputs (task=log_message)
|
|
28
|
+
[1;36m⚬[0m Main execution (2.884s)
|
|
10
29
|
[1;36m⚬[0m Main block completed
|
|
11
|
-
[1;36m⚬[0m Main block execution completed (result={message: "
|
|
12
|
-
|
|
13
|
-
[
|
|
14
|
-
|
|
15
|
-
|
|
30
|
+
[1;36m⚬[0m Main block execution completed (result={message: "Task completed successfully"})
|
|
31
|
+
Task completed successfully
|
|
32
|
+
[1;36m⚬[0m Initial task completed - entering idle state
|
data/synth/002/Makefile
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
.PHONY: create code logs clean
|
|
2
2
|
|
|
3
|
-
AGENT :=
|
|
3
|
+
AGENT := s002
|
|
4
4
|
AICTL := bundle exec ../../bin/aictl agent
|
|
5
|
+
TOOLS := workspace
|
|
5
6
|
|
|
6
7
|
create:
|
|
7
8
|
cat agent.txt | $(AICTL) create --name $(AGENT)
|
|
@@ -12,5 +13,12 @@ code:
|
|
|
12
13
|
logs:
|
|
13
14
|
$(AICTL) logs $(AGENT)
|
|
14
15
|
|
|
16
|
+
inspect:
|
|
17
|
+
$(AICTL) inspect $(AGENT)
|
|
18
|
+
|
|
15
19
|
clean:
|
|
16
|
-
$(AICTL) delete $(AGENT)
|
|
20
|
+
$(AICTL) delete $(AGENT)
|
|
21
|
+
|
|
22
|
+
save:
|
|
23
|
+
$(AICTL) code $(AGENT) --raw > agent.rb
|
|
24
|
+
$(AICTL) logs $(AGENT) > output.log
|
data/synth/003/Makefile
CHANGED
|
@@ -18,7 +18,7 @@ code:
|
|
|
18
18
|
$(AICTL) code $(AGENT)
|
|
19
19
|
|
|
20
20
|
optimize:
|
|
21
|
-
$(AICTL) optimize $(AGENT)
|
|
21
|
+
OTEL_QUERY_ENDPOINT=$(OTEL_QUERY_ENDPOINT) OTEL_QUERY_API_KEY=$(OTEL_QUERY_API_KEY) OTEL_QUERY_BACKEND=$(OTEL_QUERY_BACKEND) $(AICTL) optimize $(AGENT)
|
|
22
22
|
|
|
23
23
|
logs:
|
|
24
24
|
$(AICTL) logs $(AGENT)
|
data/synth/003/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# 003 -
|
|
1
|
+
# 003 - Progressive Synthesis & Learning
|
|
2
2
|
|
|
3
3
|
## Instructions
|
|
4
4
|
|
|
@@ -6,183 +6,255 @@
|
|
|
6
6
|
|
|
7
7
|
## Significance
|
|
8
8
|
|
|
9
|
-
This
|
|
9
|
+
This validates the complete progressive synthesis lifecycle defined in DSL v1: initial synthesis → execution → pattern detection → re-synthesis with learned symbolic implementations.
|
|
10
10
|
|
|
11
|
-
While
|
|
11
|
+
While tests 001 and 002 validated basic synthesis and neural execution, this test validates that the system can observe execution patterns and generate optimized symbolic implementations while preserving task contracts.
|
|
12
12
|
|
|
13
|
-
|
|
13
|
+
This is the first end-to-end test of the organic function learning mechanism.
|
|
14
14
|
|
|
15
|
-
|
|
15
|
+
## What This Demonstrates
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
- ✅ **File reading** - Check if story file exists and read current content
|
|
19
|
-
- ✅ **File writing** - Append new sentences to the story
|
|
20
|
-
- ✅ **Stateful execution** - Each run builds on previous runs
|
|
21
|
-
- ✅ **Standard Ruby File APIs** - Use `File.read`, `File.write`, etc.
|
|
17
|
+
### 1. Initial Synthesis (agent.synthesized.rb)
|
|
22
18
|
|
|
23
|
-
|
|
19
|
+
Three neural tasks with no explicit implementations:
|
|
24
20
|
|
|
25
21
|
```ruby
|
|
26
|
-
|
|
27
|
-
|
|
22
|
+
task :read_existing_story,
|
|
23
|
+
instructions: "Read the story.txt file from workspace...",
|
|
24
|
+
inputs: {},
|
|
25
|
+
outputs: { content: 'string', sentence_count: 'integer' }
|
|
26
|
+
|
|
27
|
+
task :generate_next_sentence,
|
|
28
|
+
instructions: "Generate exactly one new sentence...",
|
|
29
|
+
inputs: { existing_content: 'string' },
|
|
30
|
+
outputs: { sentence: 'string' }
|
|
31
|
+
|
|
32
|
+
task :append_to_story,
|
|
33
|
+
instructions: "Append the new sentence to story.txt...",
|
|
34
|
+
inputs: { sentence: 'string' },
|
|
35
|
+
outputs: { success: 'boolean', total_sentences: 'integer' }
|
|
36
|
+
|
|
37
|
+
main do |inputs|
|
|
38
|
+
story_data = execute_task(:read_existing_story)
|
|
39
|
+
new_sentence = execute_task(:generate_next_sentence,
|
|
40
|
+
inputs: { existing_content: story_data[:content] })
|
|
41
|
+
result = execute_task(:append_to_story,
|
|
42
|
+
inputs: { sentence: new_sentence[:sentence] })
|
|
43
|
+
{ sentence: new_sentence[:sentence], total: result[:total_sentences] }
|
|
44
|
+
end
|
|
28
45
|
```
|
|
29
46
|
|
|
30
|
-
|
|
31
|
-
- ✅ **Persistent storage** - Workspace directory survives pod restarts
|
|
32
|
-
- ✅ **Cumulative behavior** - Each execution reads previous state, adds to it
|
|
33
|
-
- ✅ **Multi-run workflows** - Tasks that span multiple scheduled executions
|
|
47
|
+
### 2. Pattern Detection
|
|
34
48
|
|
|
35
|
-
|
|
49
|
+
After execution, the system analyzes traces and detects:
|
|
50
|
+
- `:read_existing_story` - Deterministic file I/O pattern
|
|
51
|
+
- `:generate_next_sentence` - Creative task, no consistent pattern
|
|
52
|
+
- `:append_to_story` - Deterministic file I/O pattern
|
|
36
53
|
|
|
37
|
-
|
|
38
|
-
┌─────────────────────────────────────────────────────────┐
|
|
39
|
-
│ Kubernetes CronJob Triggers (every hour) │
|
|
40
|
-
│ Pod starts with mounted workspace volume │
|
|
41
|
-
└────────────────────┬────────────────────────────────────┘
|
|
42
|
-
│
|
|
43
|
-
▼
|
|
44
|
-
┌─────────────────────────────────────────────────────────┐
|
|
45
|
-
│ Agent Runtime Loads │
|
|
46
|
-
│ Mode: scheduled → Execute once and exit │
|
|
47
|
-
└────────────────────┬────────────────────────────────────┘
|
|
48
|
-
│
|
|
49
|
-
▼
|
|
50
|
-
┌─────────────────────────────────────────────────────────┐
|
|
51
|
-
│ main Block Executes │
|
|
52
|
-
│ 1. Check if story.txt exists in workspace │
|
|
53
|
-
│ 2. Read existing content (if any) │
|
|
54
|
-
│ 3. Execute task to generate next sentence │
|
|
55
|
-
│ 4. Append sentence to story.txt │
|
|
56
|
-
└────────────────────┬────────────────────────────────────┘
|
|
57
|
-
│
|
|
58
|
-
▼
|
|
59
|
-
┌─────────────────────────────────────────────────────────┐
|
|
60
|
-
│ File persisted to workspace volume │
|
|
61
|
-
│ Pod exits → Kubernetes waits for next hour │
|
|
62
|
-
└─────────────────────────────────────────────────────────┘
|
|
63
|
-
│
|
|
64
|
-
▼
|
|
65
|
-
┌─────────────────────────────────────────────────────────┐
|
|
66
|
-
│ Next Hour: New pod starts │
|
|
67
|
-
│ Same workspace volume mounted │
|
|
68
|
-
│ Reads previous content, adds new sentence │
|
|
69
|
-
└─────────────────────────────────────────────────────────┘
|
|
70
|
-
```
|
|
54
|
+
### 3. Re-Synthesis with Learned Implementations (agent.optimized.rb)
|
|
71
55
|
|
|
72
|
-
|
|
56
|
+
Two tasks converted to symbolic, one kept neural:
|
|
73
57
|
|
|
74
|
-
|
|
58
|
+
```ruby
|
|
59
|
+
# Learned symbolic implementation
|
|
60
|
+
task :read_existing_story,
|
|
61
|
+
inputs: {},
|
|
62
|
+
outputs: { content: 'string', sentence_count: 'integer' }
|
|
63
|
+
do |inputs|
|
|
64
|
+
file_info = execute_tool('get_file_info', { path: 'story.txt' })
|
|
65
|
+
if file_info.is_a?(Hash) && file_info[:error]
|
|
66
|
+
{ content: '', sentence_count: 0 }
|
|
67
|
+
else
|
|
68
|
+
content = execute_tool('read_file', { path: 'story.txt' })
|
|
69
|
+
sentence_count = content.split(/[.!?]+\s*/).length
|
|
70
|
+
{ content: content, sentence_count: sentence_count }
|
|
71
|
+
end
|
|
72
|
+
end
|
|
75
73
|
|
|
76
|
-
|
|
74
|
+
# Kept neural - creative task
|
|
75
|
+
task :generate_next_sentence,
|
|
76
|
+
instructions: "Generate exactly one new sentence...",
|
|
77
|
+
inputs: { existing_content: 'string' },
|
|
78
|
+
outputs: { sentence: 'string' }
|
|
79
|
+
|
|
80
|
+
# Learned symbolic implementation
|
|
81
|
+
task :append_to_story,
|
|
82
|
+
inputs: { sentence: 'string' },
|
|
83
|
+
outputs: { success: 'boolean', total_sentences: 'integer' }
|
|
84
|
+
do |inputs|
|
|
85
|
+
existing_content = execute_tool('read_file', { path: 'story.txt' })
|
|
86
|
+
content_to_write = existing_content.empty? ?
|
|
87
|
+
inputs[:sentence] : "\n#{inputs[:sentence]}"
|
|
88
|
+
execute_tool('write_file', {
|
|
89
|
+
path: 'story.txt',
|
|
90
|
+
content: existing_content + content_to_write
|
|
91
|
+
})
|
|
92
|
+
sentences = existing_content.split("\n").reject(&:empty?)
|
|
93
|
+
{ success: true, total_sentences: sentences.length + 1 }
|
|
94
|
+
end
|
|
77
95
|
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
96
|
+
# Main block UNCHANGED - contract preservation works
|
|
97
|
+
main do |inputs|
|
|
98
|
+
story_data = execute_task(:read_existing_story)
|
|
99
|
+
new_sentence = execute_task(:generate_next_sentence,
|
|
100
|
+
inputs: { existing_content: story_data[:content] })
|
|
101
|
+
result = execute_task(:append_to_story,
|
|
102
|
+
inputs: { sentence: new_sentence[:sentence] })
|
|
103
|
+
{ sentence: new_sentence[:sentence], total: result[:total_sentences] }
|
|
104
|
+
end
|
|
105
|
+
```
|
|
82
106
|
|
|
83
|
-
|
|
84
|
-
- Accumulate data over time
|
|
85
|
-
- Build complex artifacts across multiple runs
|
|
86
|
-
- Enable learning and evolution
|
|
107
|
+
### 4. Contract Stability
|
|
87
108
|
|
|
88
|
-
|
|
109
|
+
The key validation: **The `main` block is identical in both versions.**
|
|
89
110
|
|
|
90
|
-
This
|
|
111
|
+
This proves the organic function concept:
|
|
112
|
+
- Task contracts (`inputs`/`outputs`) are stable
|
|
113
|
+
- Implementations evolve (neural → symbolic)
|
|
114
|
+
- Callers are unaffected (no breaking changes)
|
|
91
115
|
|
|
92
|
-
|
|
93
|
-
2. **Data Collection Pipelines** - Append to datasets on each run
|
|
94
|
-
3. **Monitoring & Alerting** - Track state changes across time
|
|
95
|
-
4. **Creative Projects** - Build stories, documents, code incrementally
|
|
96
|
-
5. **Learning Systems** - Store observations and improve over time
|
|
116
|
+
### 5. Scheduled Execution with State
|
|
97
117
|
|
|
98
|
-
|
|
118
|
+
```ruby
|
|
119
|
+
mode :scheduled
|
|
120
|
+
schedule "0 * * * *" # Every hour
|
|
121
|
+
```
|
|
99
122
|
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
123
|
+
Each execution:
|
|
124
|
+
1. Reads existing story from workspace
|
|
125
|
+
2. Generates new sentence
|
|
126
|
+
3. Appends to file
|
|
127
|
+
4. Exits
|
|
104
128
|
|
|
105
|
-
|
|
106
|
-
- Story file exists with 1 sentence
|
|
107
|
-
- Agent reads it, generates next sentence
|
|
108
|
-
- Appends: "The knight embarked on a quest to find the lost treasure."
|
|
129
|
+
File persists across executions via Kubernetes PersistentVolume.
|
|
109
130
|
|
|
110
|
-
|
|
111
|
-
- Story file exists with 2 sentences
|
|
112
|
-
- Agent reads it, generates continuation
|
|
113
|
-
- Appends: "Along the way, she met a wise old wizard."
|
|
131
|
+
## Progressive Synthesis Flow
|
|
114
132
|
|
|
115
|
-
|
|
133
|
+
```
|
|
134
|
+
User Instruction (agent.txt)
|
|
135
|
+
↓
|
|
136
|
+
Initial Synthesis → agent.synthesized.rb
|
|
137
|
+
├─ 3 neural tasks
|
|
138
|
+
└─ main block with explicit control flow
|
|
139
|
+
↓
|
|
140
|
+
Execution (Run 1-N)
|
|
141
|
+
├─ Neural tasks call LLM
|
|
142
|
+
├─ OpenTelemetry traces collected
|
|
143
|
+
└─ Patterns emerge in execution logs
|
|
144
|
+
↓
|
|
145
|
+
Pattern Detection
|
|
146
|
+
├─ Analyze tool call sequences
|
|
147
|
+
├─ Detect deterministic behavior
|
|
148
|
+
└─ Identify tasks suitable for symbolic implementation
|
|
149
|
+
↓
|
|
150
|
+
Re-Synthesis → agent.optimized.rb
|
|
151
|
+
├─ 2 symbolic tasks (learned code)
|
|
152
|
+
├─ 1 neural task (kept creative)
|
|
153
|
+
└─ main block unchanged (contract preservation)
|
|
154
|
+
```
|
|
116
155
|
|
|
117
|
-
##
|
|
156
|
+
## Why This Matters
|
|
118
157
|
|
|
119
|
-
###
|
|
158
|
+
### Validates Core DSL v1 Concepts
|
|
120
159
|
|
|
121
|
-
-
|
|
122
|
-
- **Persistence**: Backed by Kubernetes PersistentVolume
|
|
123
|
-
- **Access**: Standard Ruby `File` and `Dir` operations
|
|
124
|
-
- **Lifecycle**: Survives pod restarts, shared across scheduled runs
|
|
160
|
+
From [requirements/proposals/dsl-v1.md](../../requirements/proposals/dsl-v1.md):
|
|
125
161
|
|
|
126
|
-
|
|
162
|
+
**1. Organic Function Abstraction**
|
|
163
|
+
- ✅ Same `execute_task()` call works for neural and symbolic tasks
|
|
164
|
+
- ✅ Contracts enforce type safety across implementations
|
|
165
|
+
- ✅ Callers are transparent to implementation changes
|
|
127
166
|
|
|
167
|
+
**2. Progressive Synthesis**
|
|
168
|
+
- ✅ Start fully neural (works immediately)
|
|
169
|
+
- ✅ Transition to hybrid (learned patterns)
|
|
170
|
+
- ✅ Preserve contracts (no breaking changes)
|
|
171
|
+
|
|
172
|
+
**3. Intelligent Optimization**
|
|
173
|
+
- ✅ System correctly identified deterministic tasks (file I/O)
|
|
174
|
+
- ✅ System correctly kept creative task neural (story generation)
|
|
175
|
+
- ✅ Generated valid symbolic Ruby code
|
|
176
|
+
|
|
177
|
+
### Enables Real-World Use Cases
|
|
178
|
+
|
|
179
|
+
**Scheduled Data Collection:**
|
|
128
180
|
```ruby
|
|
129
|
-
#
|
|
130
|
-
|
|
131
|
-
|
|
181
|
+
# Runs hourly, learns optimal fetch patterns
|
|
182
|
+
task :fetch_metrics # Neural → symbolic
|
|
183
|
+
task :analyze_data # Stays neural (complex analysis)
|
|
184
|
+
task :store_results # Neural → symbolic
|
|
185
|
+
```
|
|
132
186
|
|
|
133
|
-
|
|
134
|
-
|
|
187
|
+
**Adaptive ETL Pipelines:**
|
|
188
|
+
```ruby
|
|
189
|
+
# Extract/Transform/Load that optimizes over time
|
|
190
|
+
task :extract_source # Learns connection patterns
|
|
191
|
+
task :transform_data # Learns transformation logic
|
|
192
|
+
task :load_warehouse # Learns batch patterns
|
|
193
|
+
```
|
|
135
194
|
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
195
|
+
**Self-Optimizing Monitoring:**
|
|
196
|
+
```ruby
|
|
197
|
+
# Monitoring that improves efficiency
|
|
198
|
+
task :check_systems # Learns check sequences
|
|
199
|
+
task :analyze_anomaly # Complex pattern recognition stays neural
|
|
200
|
+
task :send_alert # Learns routing logic
|
|
140
201
|
```
|
|
141
202
|
|
|
142
|
-
##
|
|
203
|
+
## Comparison to Traditional Approaches
|
|
143
204
|
|
|
144
|
-
|
|
145
|
-
# Synthesize the agent
|
|
146
|
-
make synthesize
|
|
205
|
+
### LangChain / AutoGen / CrewAI
|
|
147
206
|
|
|
148
|
-
|
|
149
|
-
|
|
207
|
+
Static synthesis - code doesn't evolve:
|
|
208
|
+
```python
|
|
209
|
+
# Once generated, frozen forever
|
|
210
|
+
def fetch_data():
|
|
211
|
+
# ... implementation ...
|
|
150
212
|
|
|
151
|
-
#
|
|
152
|
-
make exec # Run 1
|
|
153
|
-
make exec # Run 2
|
|
154
|
-
make exec # Run 3
|
|
213
|
+
# To optimize, must rewrite and update all callers
|
|
155
214
|
```
|
|
156
215
|
|
|
157
|
-
|
|
216
|
+
### Language Operator (Organic Functions)
|
|
158
217
|
|
|
159
|
-
|
|
218
|
+
Living synthesis - code improves through observation:
|
|
219
|
+
```ruby
|
|
220
|
+
# Version 1: Neural (works immediately)
|
|
221
|
+
task :fetch_data,
|
|
222
|
+
instructions: "...",
|
|
223
|
+
outputs: { data: 'array' }
|
|
224
|
+
|
|
225
|
+
# Version 2: Symbolic (after learning)
|
|
226
|
+
task :fetch_data,
|
|
227
|
+
outputs: { data: 'array' }
|
|
228
|
+
do |inputs|
|
|
229
|
+
execute_tool('database', 'query', ...)
|
|
230
|
+
end
|
|
160
231
|
|
|
161
|
-
|
|
162
|
-
|
|
232
|
+
# Callers never change - contract is stable
|
|
233
|
+
```
|
|
163
234
|
|
|
164
|
-
|
|
165
|
-
The agent must pass the growing story as context to generate coherent continuations. This tests context window management.
|
|
235
|
+
## Files Generated
|
|
166
236
|
|
|
167
|
-
|
|
168
|
-
|
|
237
|
+
| File | Purpose |
|
|
238
|
+
|------|---------|
|
|
239
|
+
| `agent.txt` | Natural language instruction |
|
|
240
|
+
| `agent.synthesized.rb` | Initial neural agent |
|
|
241
|
+
| `agent.optimized.rb` | Learned hybrid agent |
|
|
242
|
+
| `Makefile` | Synthesis/execution commands |
|
|
169
243
|
|
|
170
|
-
|
|
171
|
-
Demonstrates workflows that unfold over hours/days, not just seconds.
|
|
244
|
+
## Synthesis Commands
|
|
172
245
|
|
|
173
|
-
|
|
246
|
+
```bash
|
|
247
|
+
# Initial synthesis (neural agent)
|
|
248
|
+
make synthesize
|
|
249
|
+
|
|
250
|
+
# Execute agent
|
|
251
|
+
make exec
|
|
174
252
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
- ✅ Each sentence is contextually coherent with previous sentences
|
|
179
|
-
- ✅ File persists across multiple runs
|
|
180
|
-
- ✅ No errors in scheduled execution
|
|
253
|
+
# Analyze traces and generate optimized version
|
|
254
|
+
make optimize
|
|
255
|
+
```
|
|
181
256
|
|
|
182
|
-
##
|
|
257
|
+
## Related Tests
|
|
183
258
|
|
|
184
|
-
|
|
185
|
-
-
|
|
186
|
-
- **Data analysis** - Accumulate findings in structured files
|
|
187
|
-
- **Version control integration** - Track changes over time
|
|
188
|
-
- **Collaboration** - Multiple agents reading/writing shared files
|
|
259
|
+
- [001 - Minimal Synthesis](../001/README.md) - Basic synthesis validation
|
|
260
|
+
- [002 - Neural Execution](../002/README.md) - Neural task execution
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require 'language_operator'
|
|
2
|
+
|
|
3
|
+
agent "s003" do
|
|
4
|
+
description "Build a story one sentence at a time, with one new sentence every hour"
|
|
5
|
+
mode :scheduled
|
|
6
|
+
schedule "0 * * * *"
|
|
7
|
+
|
|
8
|
+
task :read_existing_story,
|
|
9
|
+
inputs: { },
|
|
10
|
+
outputs: { content: 'string', sentence_count: 'integer' } do |inputs|
|
|
11
|
+
file_info = execute_tool('get_file_info', { path: 'story.txt' })
|
|
12
|
+
if file_info.is_a?(Hash) && file_info[:error]
|
|
13
|
+
{ content: '', sentence_count: 0 }
|
|
14
|
+
else
|
|
15
|
+
content = execute_tool('read_file', { path: 'story.txt' })
|
|
16
|
+
sentence_count = content.split(/[.!?]+\s*/).length
|
|
17
|
+
{ content: content, sentence_count: sentence_count }
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
task :generate_next_sentence,
|
|
22
|
+
instructions: "Generate exactly one new sentence to continue this story. Maintain consistent tone and style. Only output the new sentence.",
|
|
23
|
+
inputs: { existing_content: 'string' },
|
|
24
|
+
outputs: { sentence: 'string' }
|
|
25
|
+
|
|
26
|
+
task :append_to_story,
|
|
27
|
+
inputs: { sentence: 'string' },
|
|
28
|
+
outputs: { success: 'boolean', total_sentences: 'integer' } do |inputs|
|
|
29
|
+
existing_content = execute_tool('read_file', { path: 'story.txt' })
|
|
30
|
+
|
|
31
|
+
# Determine if we need to add a newline before appending
|
|
32
|
+
content_to_write = if existing_content.empty?
|
|
33
|
+
inputs[:sentence]
|
|
34
|
+
else
|
|
35
|
+
"\n#{inputs[:sentence]}"
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
# Append the new sentence to the file
|
|
39
|
+
execute_tool('write_file', { path: 'story.txt', content: existing_content + content_to_write })
|
|
40
|
+
|
|
41
|
+
# Count total sentences by splitting on newlines and filtering empty lines
|
|
42
|
+
sentences = existing_content.split("\n").reject(&:empty?)
|
|
43
|
+
new_sentence_count = sentences.length + 1
|
|
44
|
+
|
|
45
|
+
{ success: true, total_sentences: new_sentence_count }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
main do |inputs|
|
|
49
|
+
story_data = execute_task(:read_existing_story)
|
|
50
|
+
new_sentence = execute_task(:generate_next_sentence,
|
|
51
|
+
inputs: { existing_content: story_data[:content] })
|
|
52
|
+
result = execute_task(:append_to_story,
|
|
53
|
+
inputs: { sentence: new_sentence[:sentence] })
|
|
54
|
+
{ sentence: new_sentence[:sentence], total: result[:total_sentences] }
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
constraints do
|
|
58
|
+
max_iterations 999999
|
|
59
|
+
timeout "10m"
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
output do |outputs|
|
|
63
|
+
puts "Added sentence: #{outputs[:sentence]}"
|
|
64
|
+
puts "Story now has #{outputs[:total]} sentences"
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require 'language_operator'
|
|
2
|
+
|
|
3
|
+
agent "s003" do
|
|
4
|
+
description "Build a story one sentence at a time, with one new sentence every hour"
|
|
5
|
+
mode :scheduled
|
|
6
|
+
schedule "0 * * * *"
|
|
7
|
+
|
|
8
|
+
task :read_existing_story,
|
|
9
|
+
instructions: "Read the story.txt file from workspace. If it doesn't exist, return empty string. Return the content and count of sentences.",
|
|
10
|
+
inputs: {},
|
|
11
|
+
outputs: { content: 'string', sentence_count: 'integer' }
|
|
12
|
+
|
|
13
|
+
task :generate_next_sentence,
|
|
14
|
+
instructions: "Generate exactly one new sentence to continue this story. Maintain consistent tone and style. Only output the new sentence.",
|
|
15
|
+
inputs: { existing_content: 'string' },
|
|
16
|
+
outputs: { sentence: 'string' }
|
|
17
|
+
|
|
18
|
+
task :append_to_story,
|
|
19
|
+
instructions: "Append the new sentence to story.txt in workspace. If the file has existing content, add a newline first.",
|
|
20
|
+
inputs: { sentence: 'string' },
|
|
21
|
+
outputs: { success: 'boolean', total_sentences: 'integer' }
|
|
22
|
+
|
|
23
|
+
main do |inputs|
|
|
24
|
+
story_data = execute_task(:read_existing_story)
|
|
25
|
+
new_sentence = execute_task(:generate_next_sentence,
|
|
26
|
+
inputs: { existing_content: story_data[:content] })
|
|
27
|
+
result = execute_task(:append_to_story,
|
|
28
|
+
inputs: { sentence: new_sentence[:sentence] })
|
|
29
|
+
{ sentence: new_sentence[:sentence], total: result[:total_sentences] }
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
constraints do
|
|
33
|
+
max_iterations 999999
|
|
34
|
+
timeout "10m"
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
output do |outputs|
|
|
38
|
+
puts "Added sentence: #{outputs[:sentence]}"
|
|
39
|
+
puts "Story now has #{outputs[:total]} sentences"
|
|
40
|
+
end
|
|
41
|
+
end
|