maqam 0.1.2 → 0.1.3

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.
package/README.md CHANGED
@@ -2,9 +2,9 @@
2
2
 
3
3
  ![Maqam governed agent framework hero](app/assets/maqam-readme-hero.png)
4
4
 
5
- Maqam is an MIT-licensed Ajnas agent framework for governed workflows. It combines a local agent runtime, policy engine, evidence ledger, skill registry, tool gateway, human-review-ready approval errors, and a crawler-backed research workflow.
5
+ Maqam is an MIT-licensed Ajnas agent framework for governed workflows. It combines a local agent runtime, policy engine, evidence ledger, skill registry, tool gateway, generic agent adapter, human-review-ready approval errors, and a crawler-backed research workflow.
6
6
 
7
- The crawler is no longer the product center; it is the first governed connector. Maqam is meant for enterprise agent workflows that need inspectable runs, source-backed outputs, compliance-friendly defaults, and no required hosted service.
7
+ The crawler is not the product center; it is only the first built-in connector. Maqam can govern any agent or tool you register through `ToolGateway`, including function agents, object agents with `run`/`invoke`/`call`, browser agents, research agents, internal SaaS connectors, and write-action agents that need human approval.
8
8
 
9
9
  Full documentation: [docs/usage.md](https://github.com/AjnasNB/maqam/blob/main/docs/usage.md)
10
10
 
@@ -16,6 +16,7 @@ Full documentation: [docs/usage.md](https://github.com/AjnasNB/maqam/blob/main/d
16
16
  - `PolicyEngine`: deterministic goal and tool-call decisions for allowed tools, origins, limits, and approval gates.
17
17
  - `EvidenceLedger`: provenance records, claim links, source hashes, confidence, and unsupported-claim checks.
18
18
  - `ToolGateway`: one governed path for external tool execution.
19
+ - `createAgentTool`: wraps any function agent or object agent so Maqam can control it through policy, trace, approval, and evidence.
19
20
  - `SkillRegistry`: lightweight skill metadata registration and selection.
20
21
  - `createResearchWorkflow`: crawler-backed source collection, synthesis, and quality checks.
21
22
  - `maqam`: local web console for running governed research workflows.
@@ -80,18 +81,22 @@ import {
80
81
  EvidenceLedger,
81
82
  PolicyEngine,
82
83
  ToolGateway,
84
+ createAgentTool,
83
85
  createCrawlerTool,
84
86
  createResearchWorkflow
85
87
  } from "maqam";
86
88
 
87
89
  const evidenceLedger = new EvidenceLedger();
88
90
  const policyEngine = new PolicyEngine({
89
- allowedTools: ["crawler"],
91
+ allowedTools: ["crawler", "summarizer"],
90
92
  allowedOrigins: ["https://github.com", "https://www.npmjs.com"]
91
93
  });
92
94
 
93
95
  const gateway = new ToolGateway({ policyEngine, evidenceLedger });
94
96
  gateway.registerTool("crawler", createCrawlerTool());
97
+ gateway.registerTool("summarizer", createAgentTool(async (input) => ({
98
+ summary: `Reviewed ${input.topic}`
99
+ }), { name: "summarizer" }));
95
100
 
96
101
  const runtime = new AgentRuntime({ policyEngine, evidenceLedger, toolGateway: gateway });
97
102
  const result = await runtime.runWorkflow(
@@ -101,7 +106,7 @@ const result = await runtime.runWorkflow(
101
106
  }),
102
107
  {
103
108
  objective: "Research permissive OSS agent framework projects",
104
- allowedTools: ["crawler"],
109
+ allowedTools: ["crawler", "summarizer"],
105
110
  allowedOrigins: ["https://github.com"]
106
111
  }
107
112
  );
package/docs/usage.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Maqam Usage Guide
2
2
 
3
- Maqam is an MIT-licensed Ajnas agent framework for governed workflows. It gives you a small local runtime for building agent systems that can be inspected, policy-checked, and connected to evidence.
3
+ Maqam is an MIT-licensed Ajnas agent framework for governed workflows. It gives you a small local runtime for building agent systems that can be inspected, policy-checked, and connected to evidence. The crawler is only one built-in connector; Maqam can also govern arbitrary agents and tools through `createAgentTool` and `ToolGateway`.
4
4
 
5
5
  This guide covers installation, CLI usage, SDK usage, the local console, crawler usage, API reference, common patterns, and troubleshooting.
6
6
 
@@ -14,6 +14,7 @@ This guide covers installation, CLI usage, SDK usage, the local console, crawler
14
14
  - [Architecture](#architecture)
15
15
  - [API Reference](#api-reference)
16
16
  - [Build A Custom Workflow](#build-a-custom-workflow)
17
+ - [Control Any Agent](#control-any-agent)
17
18
  - [Register A Custom Tool](#register-a-custom-tool)
18
19
  - [Use Policy And Approvals](#use-policy-and-approvals)
19
20
  - [Use Evidence And Claims](#use-evidence-and-claims)
@@ -77,18 +78,22 @@ import {
77
78
  EvidenceLedger,
78
79
  PolicyEngine,
79
80
  ToolGateway,
81
+ createAgentTool,
80
82
  createCrawlerTool,
81
83
  createResearchWorkflow
82
84
  } from "maqam";
83
85
 
84
86
  const evidenceLedger = new EvidenceLedger();
85
87
  const policyEngine = new PolicyEngine({
86
- allowedTools: ["crawler"],
88
+ allowedTools: ["crawler", "summarizer"],
87
89
  allowedOrigins: ["https://github.com"]
88
90
  });
89
91
 
90
92
  const toolGateway = new ToolGateway({ policyEngine, evidenceLedger });
91
93
  toolGateway.registerTool("crawler", createCrawlerTool());
94
+ toolGateway.registerTool("summarizer", createAgentTool(async (input) => ({
95
+ summary: `Reviewed ${input.topic}`
96
+ }), { name: "summarizer" }));
92
97
 
93
98
  const runtime = new AgentRuntime({ policyEngine, evidenceLedger, toolGateway });
94
99
  const result = await runtime.runWorkflow(
@@ -98,7 +103,7 @@ const result = await runtime.runWorkflow(
98
103
  }),
99
104
  {
100
105
  objective: "Research Maqam from public sources",
101
- allowedTools: ["crawler"],
106
+ allowedTools: ["crawler", "summarizer"],
102
107
  allowedOrigins: ["https://github.com"],
103
108
  budget: { maxToolCalls: 20, maxRuntimeMs: 120_000 }
104
109
  }
@@ -210,6 +215,7 @@ import {
210
215
  PolicyEngine,
211
216
  ToolGateway,
212
217
  SkillRegistry,
218
+ createAgentTool,
213
219
  createCrawlerTool,
214
220
  createResearchWorkflow,
215
221
  crawl,
@@ -245,6 +251,7 @@ Core objects:
245
251
  - `AgentRuntime`: owns workflow execution.
246
252
  - `PolicyEngine`: decides what is allowed, denied, or approval-gated.
247
253
  - `ToolGateway`: routes all external tool calls through policy.
254
+ - `createAgentTool`: wraps arbitrary agents so they can be governed like any other tool.
248
255
  - `EvidenceLedger`: stores source evidence and claim support.
249
256
  - `SkillRegistry`: stores skill metadata and selects matching skills.
250
257
  - `createResearchWorkflow`: bundled workflow for public web research.
@@ -560,6 +567,69 @@ await toolGateway.call("crawler", {
560
567
  });
561
568
  ```
562
569
 
570
+ ### `createAgentTool(agent, options)`
571
+
572
+ Wraps an arbitrary agent so it can be controlled by Maqam policy and executed through `ToolGateway`.
573
+
574
+ Supported agent shapes:
575
+
576
+ - Function agent: `async (input, context) => output`
577
+ - Object agent with `run(input, context)`
578
+ - Object agent with `invoke(input, context)`
579
+ - Object agent with `call(input, context)`
580
+
581
+ ```js
582
+ const summarizer = createAgentTool(async (input, context) => {
583
+ return {
584
+ summary: `Reviewed ${input.topic}`,
585
+ evidence: [
586
+ {
587
+ evidenceId: "ev_agent_1",
588
+ sourceType: "agent_output",
589
+ source: "summarizer",
590
+ excerpt: "The agent reviewed policy and evidence controls.",
591
+ confidence: 0.8
592
+ }
593
+ ],
594
+ claims: [
595
+ {
596
+ text: "The summarizer reviewed policy and evidence controls.",
597
+ evidenceIds: ["ev_agent_1"],
598
+ confidence: 0.8
599
+ }
600
+ ]
601
+ };
602
+ }, { name: "summarizer" });
603
+
604
+ toolGateway.registerTool("summarizer", summarizer);
605
+
606
+ const result = await toolGateway.call("summarizer", {
607
+ topic: "Maqam"
608
+ }, {
609
+ runId: "run_1",
610
+ taskId: "summarize"
611
+ });
612
+ ```
613
+
614
+ If the agent output includes `evidence` or `claims` arrays, Maqam records them into the active `EvidenceLedger`.
615
+
616
+ Object-agent example:
617
+
618
+ ```js
619
+ const browserAgent = {
620
+ async run(input) {
621
+ return {
622
+ url: input.url,
623
+ result: "Browser task completed"
624
+ };
625
+ }
626
+ };
627
+
628
+ toolGateway.registerTool("browserAgent", createAgentTool(browserAgent, {
629
+ name: "browserAgent"
630
+ }));
631
+ ```
632
+
563
633
  ### `createResearchWorkflow(options)`
564
634
 
565
635
  Creates the bundled public research workflow.
@@ -741,6 +811,102 @@ console.log(result.outputs.record_summary);
741
811
  console.log(result.evidence.unsupportedClaims);
742
812
  ```
743
813
 
814
+ ## Control Any Agent
815
+
816
+ Yes, Maqam can control agents beyond crawling. The pattern is:
817
+
818
+ 1. Wrap the agent with `createAgentTool`.
819
+ 2. Register it in `ToolGateway`.
820
+ 3. Put the agent name in `PolicyEngine.allowedTools`.
821
+ 4. Add it to `approvalRequiredTools` if it can write, publish, send, modify, or spend.
822
+ 5. Call it from an `AgentRuntime` workflow task.
823
+
824
+ Example with multiple agents:
825
+
826
+ ```js
827
+ import {
828
+ AgentRuntime,
829
+ EvidenceLedger,
830
+ PolicyEngine,
831
+ ToolGateway,
832
+ createAgentTool
833
+ } from "maqam";
834
+
835
+ const evidenceLedger = new EvidenceLedger();
836
+ const policyEngine = new PolicyEngine({
837
+ allowedTools: ["researchAgent", "reviewAgent", "publishAgent"],
838
+ approvalRequiredTools: ["publishAgent"]
839
+ });
840
+ const toolGateway = new ToolGateway({ policyEngine, evidenceLedger });
841
+
842
+ toolGateway.registerTool("researchAgent", createAgentTool(async (input) => ({
843
+ notes: `Researched ${input.topic}`,
844
+ evidence: [
845
+ {
846
+ evidenceId: "ev_research_1",
847
+ sourceType: "agent_output",
848
+ source: "researchAgent",
849
+ excerpt: `Researched ${input.topic}`,
850
+ confidence: 0.7
851
+ }
852
+ ]
853
+ }), { name: "researchAgent" }));
854
+
855
+ toolGateway.registerTool("reviewAgent", createAgentTool({
856
+ async run(input) {
857
+ return { approvedForDraft: Boolean(input.notes) };
858
+ }
859
+ }, { name: "reviewAgent" }));
860
+
861
+ toolGateway.registerTool("publishAgent", createAgentTool(async () => ({
862
+ published: true
863
+ }), { name: "publishAgent" }));
864
+
865
+ const workflow = {
866
+ name: "multi_agent_governed_flow",
867
+ tasks: [
868
+ {
869
+ id: "research",
870
+ run: (context) => context.tools.call("researchAgent", { topic: "Maqam" }, context)
871
+ },
872
+ {
873
+ id: "review",
874
+ run: (context) => context.tools.call("reviewAgent", context.outputs.research, context)
875
+ },
876
+ {
877
+ id: "publish",
878
+ run: (context) => context.tools.call("publishAgent", context.outputs.review, context)
879
+ }
880
+ ]
881
+ };
882
+
883
+ const runtime = new AgentRuntime({ policyEngine, evidenceLedger, toolGateway });
884
+ const result = await runtime.runWorkflow(workflow, {
885
+ objective: "Run a governed multi-agent workflow",
886
+ allowedTools: ["researchAgent", "reviewAgent", "publishAgent"]
887
+ });
888
+
889
+ console.log(result.status);
890
+ ```
891
+
892
+ In this example, `publishAgent` will throw `ApprovalRequiredError` because it is approval-gated. That is intentional: Maqam controls the agent rather than letting it publish directly.
893
+
894
+ What Maqam can control:
895
+
896
+ - Function agents.
897
+ - LangChain/LangGraph-style agents if exposed through `invoke` or wrapped in a function.
898
+ - OpenAI Agents SDK-style functions if wrapped in a function.
899
+ - Browser agents.
900
+ - Research agents.
901
+ - GitHub/npm/internal API agents.
902
+ - Email, Slack, Jira, database, or release agents when registered as tools.
903
+
904
+ What Maqam cannot do automatically:
905
+
906
+ - It cannot control an agent you do not route through `ToolGateway`.
907
+ - It cannot make an unsafe third-party agent safe if that agent bypasses the wrapper and performs side effects internally.
908
+ - It cannot approve risky actions by itself; approval-gated actions should be routed to humans.
909
+
744
910
  ## Register A Custom Tool
745
911
 
746
912
  Tools should be small and explicit. The gateway handles policy and trace capture.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "maqam",
3
- "version": "0.1.2",
3
+ "version": "0.1.3",
4
4
  "description": "Maqam is an MIT-licensed Ajnas agent framework for governed workflows, policy, evidence, skills, and crawler-backed research.",
5
5
  "license": "MIT",
6
6
  "author": {
@@ -0,0 +1,43 @@
1
+ function resolveAgentInvoker(agent) {
2
+ if (typeof agent === "function") return agent;
3
+ if (agent && typeof agent.run === "function") return agent.run.bind(agent);
4
+ if (agent && typeof agent.invoke === "function") return agent.invoke.bind(agent);
5
+ if (agent && typeof agent.call === "function") return agent.call.bind(agent);
6
+ throw new TypeError("createAgentTool requires a function agent or an object with run, invoke, or call.");
7
+ }
8
+
9
+ function recordAgentEvidence(result, context, agentName) {
10
+ const ledger = context.evidenceLedger || context.evidence;
11
+ if (!ledger || !result || typeof result !== "object") return;
12
+
13
+ for (const item of result.evidence || []) {
14
+ ledger.addEvidence({
15
+ runId: context.runId || item.runId || null,
16
+ taskId: context.taskId || item.taskId || null,
17
+ tool: context.toolName || agentName,
18
+ ...item
19
+ });
20
+ }
21
+
22
+ for (const item of result.claims || []) {
23
+ ledger.addClaim({
24
+ runId: context.runId || item.runId || null,
25
+ taskId: context.taskId || item.taskId || null,
26
+ ...item
27
+ });
28
+ }
29
+ }
30
+
31
+ export function createAgentTool(agent, options = {}) {
32
+ const invoke = resolveAgentInvoker(agent);
33
+ const agentName = options.name || agent?.name || "agent";
34
+
35
+ return async function agentTool(input = {}, context = {}) {
36
+ const result = await invoke(input, {
37
+ ...context,
38
+ agentName
39
+ });
40
+ recordAgentEvidence(result, context, agentName);
41
+ return result;
42
+ };
43
+ }
package/src/index.js CHANGED
@@ -339,6 +339,7 @@ export { EvidenceLedger } from "./framework/evidence-ledger.js";
339
339
  export { ToolGateway } from "./framework/tool-gateway.js";
340
340
  export { SkillRegistry } from "./framework/skill-registry.js";
341
341
  export { AgentRuntime } from "./framework/runtime.js";
342
+ export { createAgentTool } from "./framework/agent-tool.js";
342
343
  export { createResearchWorkflow } from "./framework/research-workflow.js";
343
344
 
344
345
  export function createCrawlerTool(defaultOptions = {}) {