Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
The table of contents is too big for display.
Diff view
Diff view
  •  
  •  
  •  
4 changes: 4 additions & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -1 +1,5 @@
*.sh text eol=lf
*.go text eol=lf
*.golden text eol=lf
go.mod text eol=lf
go.sum text eol=lf
105 changes: 101 additions & 4 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -70,11 +70,38 @@ jobs:
exit 1
fi

quality:
runs-on: ubuntu-22.04
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
submodules: recursive

- name: Set up Go
uses: actions/setup-go@v6
with:
go-version-file: go.mod
cache: true

- name: Check dependency layers, registered skips, and repository debt
run: go test -count=1 ./core/deps

- name: Run go vet
run: go vet ./...

- name: Check whitespace and submodule pins
run: |
git diff --check HEAD
git diff --exit-code --submodule=diff
git submodule foreach --recursive 'test -z "$(git status --porcelain)"'

# ── Unit tests (depends on tidy) ──────────────────────────────

test:
runs-on: ubuntu-22.04
needs: tidy
needs: [tidy, quality]
steps:
- name: Checkout
uses: actions/checkout@v6
Expand Down Expand Up @@ -152,13 +179,66 @@ jobs:
run: |
go test -tags "re2_cgo re2_static" -race -count=1 -timeout 5m -v \
-run 'MultiRound|SendCtrlC' \
./pkg/agent/tmux/
./agent/tmux/

- name: Run agent tmux integration tests
run: |
go test -tags "re2_cgo re2_static" -race -count=1 -timeout 5m -v \
-run 'AgentTmux' \
./pkg/agent/
./agent/

windows-test:
runs-on: windows-2022
needs: [tidy, quality]
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
submodules: recursive

- name: Set up Go
uses: actions/setup-go@v6
with:
go-version-file: go.mod
cache: true

- name: Run native Windows package tests
run: go test -count=1 ./agent/... ./pkg/runner/... ./pkg/web/...

- name: Compile and test the full CLI on Windows
run: go test -count=1 -tags full ./cmd/aiscan

race-stress:
runs-on: ubuntu-22.04
needs: [tidy, quality]
steps:
- name: Checkout
uses: actions/checkout@v6
with:
fetch-depth: 0
submodules: recursive

- name: Set up Go
uses: actions/setup-go@v6
with:
go-version-file: go.mod
cache: true

- name: Repeat agent and runner concurrency tests
run: |
go test -race -count=20 -timeout 15m \
-run 'Test(ConcurrentEmitWhileRegistering|SetProviderRaceWithRun|ResetDoesNotAllowConcurrentPrompt|StreamingProviderEmitsMessageUpdates)$' \
./agent/...
go test -race -count=20 -timeout 15m \
-run 'Test(StdioSameSessionFIFOOrder|StdioSessionsRunConcurrently|StdioDrainWaitsForInFlightAndQueued|RuntimeSessionDirectLoopUsesSessionScheduler|RuntimeSessionRejectsRequestsPastPendingLimit|SessionContextCancellationStopsActiveRun|ActiveRunSteersAsyncInputWithoutSecondLifecycle)$' \
./pkg/runner/...

- name: Repeat web SSE, cancellation, and reload concurrency tests
run: |
go test -race -count=20 -timeout 20m \
-run 'Test(BroadcastAOPEventPersistsRawEnvelope|ServeSSEWithSnapshotSubscribesBeforeReadingSnapshot|ServeSSEWithSnapshotDropsQueuedSnapshotDuplicates|SessionEventsReplayHasNoSideEffects|SessionEventsResumesAfterLastEventID|CancelRemoteScanStopsAgentAndPreservesCanceledStatus|CancelQueuedScanDoesNotWaitForConcurrencySlot|CancelTaskUsesControlChannelWhenTaskQueueIsFull|CancelTaskWaitsForSaturatedControlChannel|CompleteJobCannotOverwriteCanceledScan|BroadcastConfigReload|BroadcastConfigReloadWaitsBehindCancellationFrames|HandleConfigReloadResultUpdatesAgentStatus|SaveConfigBuildFailureKeepsCommittedConfigAndCurrentApp|SaveConfigCommitFailureClosesCandidateAndKeepsCurrentApp|SaveConfigSerializesConcurrentCandidates)$' \
./pkg/web

scanner-functional:
runs-on: ubuntu-22.04
Expand Down Expand Up @@ -209,6 +289,9 @@ jobs:
go test -tags "re2_cgo re2_static" -race -count=1 -timeout 5m \
./core/resources/...

- name: Check generated resources are committed
run: git diff --exit-code

# ── E2E tests (depends on test) ───────────────────────────────

e2e:
Expand Down Expand Up @@ -240,6 +323,20 @@ jobs:
npm --prefix web/frontend run build
test -s web/static/index.html

- name: Install Playwright Chromium
working-directory: web/frontend
run: npx playwright install --with-deps chromium

- name: Run frontend Playwright E2E
working-directory: web/frontend
run: npm run test:e2e

- name: Run cyber-ui viewer tests
working-directory: web/frontend/cyber-ui
run: |
corepack pnpm install --frozen-lockfile
corepack pnpm --filter @cyber/viewer test

- name: Run e2e tests
run: |
go test -race -count=1 -timeout 10m \
Expand Down Expand Up @@ -303,7 +400,7 @@ jobs:

- name: Build all platforms (${{ matrix.id }})
run: |
for target in linux/amd64 linux/arm64 darwin/amd64 darwin/arm64 windows/amd64; do
for target in linux/amd64 linux/arm64 darwin/amd64 darwin/arm64 windows/amd64 windows/arm64; do
IFS='/' read -r goos goarch <<< "$target"
echo " compile ${goos}/${goarch}"
CGO_ENABLED=0 GOOS="$goos" GOARCH="$goarch" \
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/scanner-regression.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,4 +35,4 @@ jobs:
run: |
go test -tags "full integration re2_cgo re2_static" -count=1 -timeout 8m -v \
-run 'Test(ScannerPublicIntegration|FullScannerPublicIntegration)$' \
./pkg/tools
./tools
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@ out/
scan_results.jsonl
pw_driver_bin
node_modules/
web/frontend/playwright-report/
web/frontend/test-results/
community.yaml

# Local runtime state / operator artifacts
Expand Down
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ prepare:
mkdir -p "$(BIN_DIR)"

aop-gen:
$(GO) generate ./pkg/aop/...
$(GO) generate ./core/aop/...

frontend:
$(NPM) --prefix "$(WEB_DIR)" run build
Expand Down
21 changes: 10 additions & 11 deletions pkg/agent/agent.go → agent/agent.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ import (
"fmt"
"sync"

"github.com/chainreactors/aiscan/pkg/agent/inbox"
"github.com/chainreactors/aiscan/pkg/aop/x/delegation"
"github.com/chainreactors/aiscan/pkg/telemetry"
"github.com/chainreactors/aiscan/agent/inbox"
"github.com/chainreactors/aiscan/core/aop/x/delegation"
"github.com/chainreactors/aiscan/core/telemetry"
)

type Agent struct {
Expand Down Expand Up @@ -81,17 +81,15 @@ func (a *Agent) SessionID() string {
}

func (a *Agent) beginSession() {
a.mu.Lock()
em, model := a.Cfg.emitter, a.Cfg.Model
a.mu.Unlock()
em.sessionStart(model)
cfg := a.configSnapshot()
cfg.emitter.sessionStart(cfg.Model)
emitSessionStart(context.Background(), cfg)
}

func (a *Agent) endSession(reason string) {
a.mu.Lock()
em := a.Cfg.emitter
a.mu.Unlock()
em.sessionEnd(reason)
cfg := a.configSnapshot()
cfg.emitter.sessionEnd(reason)
emitSessionEnd(context.Background(), cfg, reason)
}

// Continue resumes the agent without a new prompt (e.g. after tool results).
Expand Down Expand Up @@ -235,6 +233,7 @@ func deriveNamedFromConfig(cfg Config, name, parentToolCallID string, detail *de
Temperature: cfg.Temperature,
CacheRetention: cfg.CacheRetention,
Bus: cfg.Bus,
Hooks: cfg.Hooks,
AgentName: name,
ParentSessionID: cfg.SessionID,
ParentToolCallID: parentToolCallID,
Expand Down
4 changes: 2 additions & 2 deletions pkg/agent/agent_test.go → agent/agent_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ import (
"testing"
"time"

"github.com/chainreactors/aiscan/pkg/aop"
"github.com/chainreactors/aiscan/core/aop"
"github.com/chainreactors/aiscan/core/telemetry"
"github.com/chainreactors/aiscan/pkg/commands"
"github.com/chainreactors/aiscan/pkg/telemetry"
"github.com/chainreactors/aiscan/skills"
)

Expand Down
4 changes: 2 additions & 2 deletions pkg/agent/aop_emit.go → agent/aop_emit.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,9 @@ import (
"sync/atomic"
"time"

"github.com/chainreactors/aiscan/core/aop"
"github.com/chainreactors/aiscan/core/aop/x/delegation"
"github.com/chainreactors/aiscan/core/eventbus"
"github.com/chainreactors/aiscan/pkg/aop"
"github.com/chainreactors/aiscan/pkg/aop/x/delegation"
)

// aopEmitter is the agent kernel's single event-emission path. Every event
Expand Down
2 changes: 1 addition & 1 deletion pkg/agent/aop_emit_test.go → agent/aop_emit_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
"sync/atomic"
"testing"

"github.com/chainreactors/aiscan/pkg/aop"
"github.com/chainreactors/aiscan/core/aop"
)

// streamEventCollector records message/message.delta events from the bus.
Expand Down
4 changes: 2 additions & 2 deletions pkg/agent/compact.go → agent/compact.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import (
"fmt"
"strings"

"github.com/chainreactors/aiscan/pkg/agent/truncate"
xcompact "github.com/chainreactors/aiscan/pkg/aop/x/compact"
xcompact "github.com/chainreactors/aiscan/core/aop/x/compact"
"github.com/chainreactors/aiscan/core/truncate"
)

const compactSystemPrompt = `You are a context summarization assistant. Your task is to read a conversation between a user and an AI assistant, then produce a structured summary following the exact format specified.
Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
2 changes: 1 addition & 1 deletion pkg/agent/defaults.go → agent/defaults.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package agent

import "github.com/chainreactors/aiscan/pkg/agent/truncate"
import "github.com/chainreactors/aiscan/core/truncate"

const (
DefaultMaxResultSize = truncate.DefaultMaxBytes
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,10 @@ import (
"strings"
"time"

agentpkg "github.com/chainreactors/aiscan/pkg/agent"
"github.com/chainreactors/aiscan/pkg/agent/provider"
"github.com/chainreactors/aiscan/pkg/agent/truncate"
"github.com/chainreactors/aiscan/pkg/telemetry"
agentpkg "github.com/chainreactors/aiscan/agent"
"github.com/chainreactors/aiscan/agent/provider"
"github.com/chainreactors/aiscan/core/telemetry"
"github.com/chainreactors/aiscan/core/truncate"
)

const (
Expand Down
8 changes: 4 additions & 4 deletions pkg/agent/evaluator/loop.go → agent/evaluator/loop.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ import (
"fmt"
"strings"

"github.com/chainreactors/aiscan/pkg/agent"
"github.com/chainreactors/aiscan/pkg/agent/provider"
xeval "github.com/chainreactors/aiscan/pkg/aop/x/eval"
"github.com/chainreactors/aiscan/pkg/telemetry"
"github.com/chainreactors/aiscan/agent"
"github.com/chainreactors/aiscan/agent/provider"
xeval "github.com/chainreactors/aiscan/core/aop/x/eval"
"github.com/chainreactors/aiscan/core/telemetry"
)

const defaultMaxEvalRounds = 3
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ import (
"context"
"testing"

"github.com/chainreactors/aiscan/agent"
"github.com/chainreactors/aiscan/agent/provider"
"github.com/chainreactors/aiscan/core/aop"
"github.com/chainreactors/aiscan/core/eventbus"
"github.com/chainreactors/aiscan/pkg/agent"
"github.com/chainreactors/aiscan/pkg/agent/provider"
"github.com/chainreactors/aiscan/pkg/aop"
)

type fixedProvider struct {
Expand Down
18 changes: 18 additions & 0 deletions agent/external_import_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package agent_test

import (
"testing"

"github.com/chainreactors/aiscan/agent"
)

func TestRootAgentPublicImport(t *testing.T) {
config := agent.Config{}.
WithModel("example-model").
WithMaxTokens(256).
WithContextWindow(4096)
if config.Model != "example-model" || config.MaxTokens != 256 || config.ContextWindow != 4096 {
t.Fatalf("root agent config aliases/builders are not externally usable: %#v", config)
}
_ = agent.ProviderConfig{Model: "example-model"}
}
File renamed without changes.
4 changes: 2 additions & 2 deletions pkg/agent/helpers_test.go → agent/helpers_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import (
"sync/atomic"
"testing"

"github.com/chainreactors/aiscan/agent/inbox"
"github.com/chainreactors/aiscan/core/aop"
"github.com/chainreactors/aiscan/core/eventbus"
"github.com/chainreactors/aiscan/core/tool"
"github.com/chainreactors/aiscan/pkg/agent/inbox"
"github.com/chainreactors/aiscan/pkg/aop"
"github.com/chainreactors/aiscan/pkg/commands"
"github.com/chainreactors/aiscan/skills"
)
Expand Down
Loading