@lazyingart/agintiflow 0.20.209 → 0.20.211

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@lazyingart/agintiflow",
3
- "version": "0.20.209",
3
+ "version": "0.20.211",
4
4
  "type": "module",
5
5
  "description": "AgInTiFlow is a project-aware agent workspace for hybrid wet-dry R&D, hardware-aware intelligence, software automation, and industrial workflows.",
6
6
  "license": "Apache-2.0",
@@ -52,6 +52,17 @@ const artifactContract = deriveScsTaskContract({
52
52
  });
53
53
  assert.equal(artifactContract.requiresExternalEvidence, true, "real chat artifact work lost its evidence gate");
54
54
  assert.ok(artifactContract.requiredEvidence.some((item) => item.category === "artifact"));
55
+ const scopedArtifactRootContract = deriveScsTaskContract({
56
+ goal:
57
+ 'AGINTI_EVIDENCE_SCOPE_JSON: {"mode":"task","request":"Create result.txt with the exact requested content.","artifact_root":"/tmp/labcanvas-task-artifacts"}',
58
+ taskProfile: "chatops",
59
+ });
60
+ assert.equal(scopedArtifactRootContract.artifactRoot, "/tmp/labcanvas-task-artifacts");
61
+ assert.deepEqual(
62
+ scopedArtifactRootContract.exactOutputPaths,
63
+ ["/tmp/labcanvas-task-artifacts/result.txt"],
64
+ "a bare task artifact filename was not resolved against the host-declared artifact root"
65
+ );
55
66
 
56
67
  let capturedPayload = null;
57
68
  const client = {
@@ -770,6 +770,41 @@ const explicitDeepResearchFollowup = selectProgressiveTools(allTools, {
770
770
  });
771
771
  assert(names(explicitDeepResearchFollowup).includes("web_search"), "deep-research follow-up did not restore targeted recovery tools");
772
772
 
773
+ const scopedArtifactPrompt = `You are a persistent workspace agent. The surrounding policy mentions an evidence review.
774
+ AGINTI_EVIDENCE_SCOPE_JSON: {"mode":"task","request":"Create one plain-text artifact and verify it."}
775
+ Repository evidence to consult as relevant: literature review, evidence review, research report.`;
776
+ const scopedArtifactTools = selectProgressiveTools(allTools, {
777
+ config: { provider: "deepseek", progressiveTools: true },
778
+ goal: scopedArtifactPrompt,
779
+ profile: "auto",
780
+ messages: [
781
+ { role: "user", content: scopedArtifactPrompt },
782
+ {
783
+ role: "user",
784
+ content: "Runtime snapshot: consult the surrounding literature review and evidence review policy before acting.",
785
+ },
786
+ ],
787
+ });
788
+ assert(names(scopedArtifactTools).includes("write_file"), "scoped artifact task omitted write_file");
789
+ assert(
790
+ !(names(scopedArtifactTools).length === 2 && names(scopedArtifactTools)[0] === "deep_research"),
791
+ "surrounding policy prose incorrectly forced a scoped artifact task into deep research"
792
+ );
793
+
794
+ const scopedDeepResearchPrompt = `Generic workspace policy.
795
+ AGINTI_EVIDENCE_SCOPE_JSON: {"mode":"task","request":"Write a deep research evidence review comparing three primary papers."}`;
796
+ const scopedDeepResearchTools = selectProgressiveTools(allTools, {
797
+ config: { provider: "deepseek", progressiveTools: true },
798
+ goal: scopedDeepResearchPrompt,
799
+ profile: "auto",
800
+ messages: [{ role: "user", content: scopedDeepResearchPrompt }],
801
+ });
802
+ sameNames(
803
+ scopedDeepResearchTools,
804
+ ["deep_research", "finish"],
805
+ "explicit deep research inside the scoped user request was not preserved"
806
+ );
807
+
773
808
  const writingTools = selectProgressiveTools(allTools, {
774
809
  config: { provider: "localllm" },
775
810
  goal: "Draft and revise a chapter, then save it.",
@@ -10,7 +10,9 @@ import { WebDatabase } from "../src/web-db.js";
10
10
 
11
11
  const repoRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), "..");
12
12
  const fixtureMcpServer = path.join(repoRoot, "scripts", "fixtures", "mcp-stdio-smoke-server.mjs");
13
- const runtimeDir = await fs.mkdtemp(path.join(os.tmpdir(), "agintiflow-api-smoke-"));
13
+ const fixtureRoot = await fs.mkdtemp(path.join(os.tmpdir(), "agintiflow-api-smoke-root-"));
14
+ const runtimeDir = path.join(fixtureRoot, "workspace");
15
+ await fs.mkdir(runtimeDir, { recursive: true });
14
16
  const agintiflowHome = path.join(runtimeDir, ".agintiflow-home");
15
17
  process.env.AGINTIFLOW_HOME = agintiflowHome;
16
18
  const port = 43000 + Math.floor(Math.random() * 1000);
@@ -863,5 +865,5 @@ try {
863
865
  } finally {
864
866
  server.kill("SIGTERM");
865
867
  await delay(150);
866
- await fs.rm(runtimeDir, { recursive: true, force: true });
868
+ await fs.rm(fixtureRoot, { recursive: true, force: true });
867
869
  }
@@ -1,4 +1,5 @@
1
1
  import { shouldStartWithDeepResearch } from "./research-routing.js";
2
+ import { hasAgintiEvidenceScope, scopedChatopsEvidenceGoal } from "./scs-evidence.js";
2
3
  import {
3
4
  INTEGRATION_TEXT_WORKSPACE_PROFILE_ID,
4
5
  isIntegrationTextWorkspaceToolAllowed,
@@ -514,15 +515,17 @@ function textContent(content) {
514
515
  }
515
516
 
516
517
  function taskText(goal, config, messages) {
517
- const recentConversation = Array.isArray(messages)
518
+ const rawGoal = goal || config.goal || "";
519
+ const scopedGoal = scopedChatopsEvidenceGoal(rawGoal);
520
+ const recentConversation = !hasAgintiEvidenceScope(rawGoal) && Array.isArray(messages)
518
521
  ? messages
519
522
  .filter((message) => message && (message.role === "user" || message.role === "assistant"))
520
523
  .slice(-6)
521
- .map((message) => textContent(message.content))
524
+ .map((message) => scopedChatopsEvidenceGoal(textContent(message.content)))
522
525
  .filter(Boolean)
523
526
  .join("\n")
524
527
  : "";
525
- return `${String(goal || config.goal || "")}\n${recentConversation}`.trim().toLowerCase();
528
+ return `${scopedGoal}\n${recentConversation}`.trim().toLowerCase();
526
529
  }
527
530
 
528
531
  function currentTaskMessages(messages) {
@@ -1,3 +1,5 @@
1
+ import { hasAgintiEvidenceScope, scopedChatopsEvidenceGoal } from "./scs-evidence.js";
2
+
1
3
  function messageText(content) {
2
4
  if (typeof content === "string") return content;
3
5
  if (!Array.isArray(content)) return "";
@@ -5,12 +7,14 @@ function messageText(content) {
5
7
  }
6
8
 
7
9
  export function hasExplicitDeepResearchIntent(goal = "", messages = []) {
8
- const recent = messages
9
- .filter((message) => message?.role === "user")
10
- .slice(-4)
11
- .map((message) => messageText(message.content))
12
- .join("\n");
13
- const text = `${String(goal || "")}\n${recent}`.toLowerCase();
10
+ const recent = hasAgintiEvidenceScope(goal)
11
+ ? ""
12
+ : messages
13
+ .filter((message) => message?.role === "user")
14
+ .slice(-4)
15
+ .map((message) => scopedChatopsEvidenceGoal(messageText(message.content)))
16
+ .join("\n");
17
+ const text = `${scopedChatopsEvidenceGoal(goal)}\n${recent}`.toLowerCase();
14
18
  return (
15
19
  /\b(deep (?:web )?research|literature review|systematic review|multi[- ]source research|evidence review)\b/i.test(text) ||
16
20
  /\b(research report|compare at least|independent (?:primary|scholarly|official) sources?)\b.{0,160}\b(primary|scholarly|papers?|pdf|citations?|evidence|sources?)\b/i.test(text) ||
@@ -670,9 +670,27 @@ function stripForbiddenLanguage(goal = "") {
670
670
  .replace(/禁止([^。\n;]+)/g, "");
671
671
  }
672
672
 
673
- function scopedChatopsEvidenceGoal(goal = "", taskProfile = "") {
674
- const match = String(goal || "").match(/^AGINTI_EVIDENCE_SCOPE_JSON:\s*(\{[^\n]+\})\s*$/m);
675
- if (!match) {
673
+ function parseAgintiEvidenceScope(goal = "") {
674
+ const matches = [
675
+ ...String(goal || "").matchAll(/^AGINTI_EVIDENCE_SCOPE_JSON:\s*(\{[^\n]+\})\s*$/gm),
676
+ ];
677
+ const match = matches.at(-1);
678
+ if (!match) return null;
679
+ try {
680
+ const payload = JSON.parse(match[1]);
681
+ return payload && typeof payload === "object" ? payload : null;
682
+ } catch {
683
+ return null;
684
+ }
685
+ }
686
+
687
+ export function hasAgintiEvidenceScope(goal = "") {
688
+ return Boolean(parseAgintiEvidenceScope(goal));
689
+ }
690
+
691
+ export function scopedChatopsEvidenceGoal(goal = "", taskProfile = "") {
692
+ const payload = parseAgintiEvidenceScope(goal);
693
+ if (!payload) {
676
694
  const text = String(goal || "");
677
695
  const lines = text
678
696
  .split(/\r?\n/)
@@ -690,22 +708,32 @@ function scopedChatopsEvidenceGoal(goal = "", taskProfile = "") {
690
708
  }
691
709
  return text;
692
710
  }
693
- try {
694
- const payload = JSON.parse(match[1]);
695
- if (!payload || typeof payload !== "object") return String(goal || "");
696
- const mode = String(payload.mode || "").trim().toLowerCase();
697
- if (["chat-response", "host-managed-response", "plan-response", "read-only-answer"].includes(mode)) {
698
- return "Answer the current chat turn directly without external execution.";
699
- }
700
- const request = String(payload.request || "").trim();
701
- return request || String(goal || "");
702
- } catch {
703
- return String(goal || "");
711
+ const mode = String(payload.mode || "").trim().toLowerCase();
712
+ if (["chat-response", "host-managed-response", "plan-response", "read-only-answer"].includes(mode)) {
713
+ return "Answer the current chat turn directly without external execution.";
704
714
  }
715
+ const request = String(payload.request || "").trim();
716
+ return request || String(goal || "");
717
+ }
718
+
719
+ function scopedArtifactRoot(goal = "") {
720
+ const payload = parseAgintiEvidenceScope(goal);
721
+ if (!payload || String(payload.mode || "").trim().toLowerCase() !== "task") return "";
722
+ return String(payload.artifact_root || "").trim();
723
+ }
724
+
725
+ function applyScopedArtifactRoot(items = [], artifactRoot = "") {
726
+ if (!artifactRoot) return items;
727
+ return items.map((item) => {
728
+ const value = String(item || "").trim();
729
+ if (!value || path.isAbsolute(value) || value.startsWith("~/") || /[\\/]/.test(value)) return value;
730
+ return path.join(artifactRoot, value);
731
+ });
705
732
  }
706
733
 
707
734
  export function deriveScsTaskContract({ goal = "", taskProfile = "", acceptanceCriteria = [] } = {}) {
708
735
  const evidenceGoal = scopedChatopsEvidenceGoal(goal, taskProfile);
736
+ const artifactRoot = scopedArtifactRoot(goal);
709
737
  const requirementCategories = inferRequirementCategories(evidenceGoal, taskProfile, acceptanceCriteria);
710
738
  const requiredToolCalls = inferRequiredToolCalls(evidenceGoal);
711
739
  const requiresExternalEvidence = requirementCategories.length > 0 || requiredToolCalls.length > 0 || goalRequiresEvidence(evidenceGoal, taskProfile);
@@ -714,8 +742,11 @@ export function deriveScsTaskContract({ goal = "", taskProfile = "", acceptanceC
714
742
  category,
715
743
  description: CATEGORY_LABELS[category] || category,
716
744
  }));
717
- const exactOutputPaths = inferExactOutputPaths(evidenceGoal);
718
- const exactInputPaths = inferExactInputPaths(evidenceGoal).filter((item) => !exactOutputPaths.includes(item));
745
+ const inferredOutputPaths = inferExactOutputPaths(evidenceGoal);
746
+ const exactOutputPaths = applyScopedArtifactRoot(inferredOutputPaths, artifactRoot);
747
+ const exactInputPaths = inferExactInputPaths(evidenceGoal).filter(
748
+ (item) => !inferredOutputPaths.includes(item) && !exactOutputPaths.includes(item)
749
+ );
719
750
  const declaredSourceRoots = inferDeclaredSourceRoots(evidenceGoal);
720
751
  return {
721
752
  version: 1,
@@ -725,6 +756,7 @@ export function deriveScsTaskContract({ goal = "", taskProfile = "", acceptanceC
725
756
  requiredEvidence,
726
757
  forbiddenActions: inferForbiddenActions(evidenceGoal),
727
758
  exactOutputPaths,
759
+ artifactRoot,
728
760
  exactInputPaths,
729
761
  declaredSourceRoots,
730
762
  readOnlyReadiness: isReadOnlyReadinessTask(evidenceGoal),
@@ -782,11 +814,12 @@ export function augmentScsTaskContractWithProjectVerification(contract = {}, sta
782
814
  .map((item) => String(item?.path || item || "").trim())
783
815
  .filter(Boolean)
784
816
  ).slice(0, 80);
785
- const requiredOutputs = unique(
817
+ const requiredOutputs = unique(applyScopedArtifactRoot(
786
818
  (Array.isArray(verification.requiredOutputs) ? verification.requiredOutputs : [])
787
819
  .map((item) => String(item || "").trim())
788
- .filter(Boolean)
789
- ).slice(0, 64);
820
+ .filter(Boolean),
821
+ String(contract.artifactRoot || "")
822
+ )).slice(0, 64);
790
823
  const requiredProjectCommands = unique(
791
824
  (Array.isArray(verification.requiredCommands) ? verification.requiredCommands : [])
792
825
  .map(normalizeProjectCommand)