Skip to content

Commit 3e69d5c

Browse files
Jayanaka-98claude
andauthored
Edit: Agentic AI with Jac (#35)
* rewrite * update * Remove horizontal-rule separators reintroduced by merge Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * Edit blog post: Agentic AI with Jac: A Programming Language That Knows What an Agent Is * video * updated --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 8c49e83 commit 3e69d5c

1 file changed

Lines changed: 40 additions & 10 deletions

File tree

docs/blog/posts/building_agentic_ai_with_jac.md

Lines changed: 40 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
---
22
date: 2026-05-12
33
authors:
4-
- jayanaka
4+
- jayanaka
55
categories:
6-
- Jac Programming
7-
- AI
6+
- Jac Programming
7+
- AI
88
slug: building-agentic-ai-with-jac
99
---
1010

@@ -14,7 +14,7 @@ Most of an agent codebase is not the agent. It is the supporting code every deve
1414

1515
<!-- more -->
1616

17-
## The Problem
17+
## The Problem
1818

1919
**The same intent gets written twice.** A tool is a function *and* a JSON schema describing it. A structured output is a Pydantic class *and* a `response_format` argument. If we rename the function but forget the JSON spec, the spec still advertises the old name to the model. If we rename a field but forget the prompt that asks for it, the prompt still references the old one. Nothing in the build catches the mismatch, because the link between the code and the string only exists in the developer's head. Drift is silent until the model misbehaves at runtime.
2020

@@ -32,7 +32,7 @@ The answer is already in the [**Jac**](https://docs.jaseci.org/) programming lan
3232

3333
!!! info "About the code"
3434

35-
Every Jac snippet below is self-contained and runs with `jac run <file>.jac` against a configured model. Copy any block, save it, and you'll see the agent execute end-to-end.
35+
Every Jac snippet below runs with `jac run <file>.jac` once a model is bound to `llm` — either project-wide in `jac.toml` or per file with `import from byllm.llm { Model }` and `glob llm = Model(model_name="openai/gpt-4o-mini");`. Complete, runnable versions of all seven patterns live in the companion repo: [**github.com/Jayanaka-98/agentic-ai-with-jac**](https://github.com/Jayanaka-98/agentic-ai-with-jac).
3636

3737
<!-- ---
3838
@@ -234,10 +234,17 @@ node Examples { def run(draft: str) -> str by llm(); }
234234
node Summary { def run(detail: str) -> str by llm(); }
235235
node Done {}
236236
237+
sem Draft.run = "Write a first-draft technical explanation of the topic.";
238+
sem Examples.run = "Revise the draft, weaving in concrete worked examples.";
239+
sem Summary.run = "Condense the text into a tight 3-4 sentence summary.";
240+
237241
walker Explainer {
238242
has topic: str;
239243
has text: str = "";
240244
245+
can begin with Root entry {
246+
visit [-->];
247+
}
241248
can do_draft with Draft entry {
242249
self.text = here.run(self.topic);
243250
visit [-->];
@@ -331,12 +338,20 @@ node Evaluate { def run(draft: str, topic: str) -> Review by llm(); }
331338
node Revise { def run(draft: str, feedback: str) -> str by llm(); }
332339
node Approved {}
333340
341+
sem Draft.run = "Write a first-draft tutorial section on the topic.";
342+
sem Evaluate.run = "Critique the draft as a tutorial on the topic and return a typed verdict.";
343+
sem Revise.run = "Rewrite the draft to address the feedback.";
344+
334345
walker TutorialWriter {
335346
has topic: str;
336347
has draft: str = "";
337348
has feedback: str = "";
338349
has version: int = 1;
339350
351+
can begin with Root entry {
352+
visit [-->];
353+
}
354+
340355
can do_draft with Draft entry {
341356
self.draft = here.run(self.topic);
342357
visit [-->];
@@ -393,6 +408,8 @@ walker HardwareResearcher {
393408
self.result = self.investigate(self.topic);
394409
}
395410
}
411+
sem HardwareResearcher.investigate = "Research the topic from a hardware angle using the tools.";
412+
396413
walker SoftwareResearcher {
397414
has topic: str;
398415
has result: str = "";
@@ -401,6 +418,8 @@ walker SoftwareResearcher {
401418
self.result = self.investigate(self.topic);
402419
}
403420
}
421+
sem SoftwareResearcher.investigate = "Research the topic from a software angle using the tools.";
422+
404423
walker AIResearcher {
405424
has topic: str;
406425
has result: str = "";
@@ -409,24 +428,31 @@ walker AIResearcher {
409428
self.result = self.investigate(self.topic);
410429
}
411430
}
431+
sem AIResearcher.investigate = "Research the topic from an AI/ML angle using the tools.";
412432
413433
walker SurveyAgent {
414434
has topic: str;
415435
has response: str = "";
416-
def synthesize(topic: str, hw: str, sw: str, ai: str) -> str by llm();
436+
def synthesize(
437+
topic: str,
438+
hw: HardwareResearcher,
439+
sw: SoftwareResearcher,
440+
ai: AIResearcher
441+
) -> str by llm();
417442
418443
can start with Root entry {
419444
hw_task = flow root spawn HardwareResearcher(topic=self.topic);
420445
sw_task = flow root spawn SoftwareResearcher(topic=self.topic);
421446
ai_task = flow root spawn AIResearcher(topic=self.topic);
422447
423-
hw: any = wait hw_task;
424-
sw: any = wait sw_task;
425-
ai: any = wait ai_task;
448+
hw: HardwareResearcher = (wait hw_task) as HardwareResearcher;
449+
sw: SoftwareResearcher = (wait sw_task) as SoftwareResearcher;
450+
ai: AIResearcher = (wait ai_task) as AIResearcher;
426451
427-
self.response = self.synthesize(self.topic, hw.result, sw.result, ai.result);
452+
self.response = self.synthesize(self.topic, hw, sw, ai);
428453
}
429454
}
455+
sem SurveyAgent.synthesize = "Combine the hardware, software, and AI research notes into one survey.";
430456
431457
with entry {
432458
root spawn SurveyAgent(topic="Efficient inference for large language models");
@@ -460,3 +486,7 @@ Those languages weren't chosen because they fit agents. They were chosen for eco
460486
!!! quote ""
461487

462488
**With these patterns in the language, building an agent is just building the agent.**
489+
490+
<div style="position: relative; width: 100%; padding-bottom: 56.25%; margin: 1.5em 0;">
491+
<iframe style="position: absolute; top: 0; left: 0; width: 100%; height: 100%;" src="https://www.youtube.com/embed/jk1OUyNnHpk?si=pVUxxajZkpf0d-zK" title="YouTube video player" frameborder="0" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" referrerpolicy="strict-origin-when-cross-origin" allowfullscreen></iframe>
492+
</div>

0 commit comments

Comments
 (0)