Skip to content
Open
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
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,9 @@
/ds4_native
/ds4_server_test
/ds4_test
/tests/ds4_agent_context_test
/tests/ds4_agent_git_test
/tests/generated/
/ds4flash.gguf
/TODO.md
/gguf/
Expand Down
32 changes: 21 additions & 11 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -57,15 +57,15 @@ ds4-bench: ds4_bench.o $(CORE_OBJS)
ds4-eval: ds4_eval.o $(CORE_OBJS)
$(CC) $(CFLAGS) -o $@ ds4_eval.o $(CORE_OBJS) $(METAL_LDLIBS)

ds4-agent: ds4_agent.o ds4_web.o ds4_kvstore.o linenoise.o $(CORE_OBJS)
$(CC) $(CFLAGS) -o $@ ds4_agent.o ds4_web.o ds4_kvstore.o linenoise.o $(CORE_OBJS) $(METAL_LDLIBS)
ds4-agent: ds4_agent.o ds4_agent_git.o ds4_web.o ds4_kvstore.o linenoise.o $(CORE_OBJS)
$(CC) $(CFLAGS) -o $@ ds4_agent.o ds4_agent_git.o ds4_web.o ds4_kvstore.o linenoise.o $(CORE_OBJS) $(METAL_LDLIBS)

cpu: ds4_cli_cpu.o ds4_server_cpu.o ds4_bench_cpu.o ds4_eval_cpu.o ds4_agent_cpu.o ds4_web.o ds4_kvstore.o linenoise.o rax.o $(CPU_CORE_OBJS)
cpu: ds4_cli_cpu.o ds4_server_cpu.o ds4_bench_cpu.o ds4_eval_cpu.o ds4_agent_cpu.o ds4_agent_git.o ds4_web.o ds4_kvstore.o linenoise.o rax.o $(CPU_CORE_OBJS)
$(CC) $(CFLAGS) -o ds4 ds4_cli_cpu.o linenoise.o $(CPU_CORE_OBJS) $(LDLIBS)
$(CC) $(CFLAGS) -o ds4-server ds4_server_cpu.o ds4_kvstore.o rax.o $(CPU_CORE_OBJS) $(LDLIBS)
$(CC) $(CFLAGS) -o ds4-bench ds4_bench_cpu.o $(CPU_CORE_OBJS) $(LDLIBS)
$(CC) $(CFLAGS) -o ds4-eval ds4_eval_cpu.o $(CPU_CORE_OBJS) $(LDLIBS)
$(CC) $(CFLAGS) -o ds4-agent ds4_agent_cpu.o ds4_web.o ds4_kvstore.o linenoise.o $(CPU_CORE_OBJS) $(LDLIBS)
$(CC) $(CFLAGS) -o ds4-agent ds4_agent_cpu.o ds4_agent_git.o ds4_web.o ds4_kvstore.o linenoise.o $(CPU_CORE_OBJS) $(LDLIBS)

cuda-regression:
@echo "cuda-regression requires a CUDA build"
Expand Down Expand Up @@ -107,15 +107,15 @@ ds4-bench: ds4_bench.o $(CORE_OBJS)
ds4-eval: ds4_eval.o $(CORE_OBJS)
$(NVCC) $(NVCCFLAGS) -o $@ $^ $(CUDA_LDLIBS)

ds4-agent: ds4_agent.o ds4_web.o ds4_kvstore.o linenoise.o $(CORE_OBJS)
ds4-agent: ds4_agent.o ds4_agent_git.o ds4_web.o ds4_kvstore.o linenoise.o $(CORE_OBJS)
$(NVCC) $(NVCCFLAGS) -o $@ $^ $(CUDA_LDLIBS)

cpu: ds4_cli_cpu.o ds4_server_cpu.o ds4_bench_cpu.o ds4_eval_cpu.o ds4_agent_cpu.o ds4_web.o ds4_kvstore.o linenoise.o rax.o $(CPU_CORE_OBJS)
cpu: ds4_cli_cpu.o ds4_server_cpu.o ds4_bench_cpu.o ds4_eval_cpu.o ds4_agent_cpu.o ds4_agent_git.o ds4_web.o ds4_kvstore.o linenoise.o rax.o $(CPU_CORE_OBJS)
$(CC) $(CFLAGS) -o ds4 ds4_cli_cpu.o linenoise.o $(CPU_CORE_OBJS) $(LDLIBS)
$(CC) $(CFLAGS) -o ds4-server ds4_server_cpu.o ds4_kvstore.o rax.o $(CPU_CORE_OBJS) $(LDLIBS)
$(CC) $(CFLAGS) -o ds4-bench ds4_bench_cpu.o $(CPU_CORE_OBJS) $(LDLIBS)
$(CC) $(CFLAGS) -o ds4-eval ds4_eval_cpu.o $(CPU_CORE_OBJS) $(LDLIBS)
$(CC) $(CFLAGS) -o ds4-agent ds4_agent_cpu.o ds4_web.o ds4_kvstore.o linenoise.o $(CPU_CORE_OBJS) $(LDLIBS)
$(CC) $(CFLAGS) -o ds4-agent ds4_agent_cpu.o ds4_agent_git.o ds4_web.o ds4_kvstore.o linenoise.o $(CPU_CORE_OBJS) $(LDLIBS)

cuda-regression: tests/cuda_long_context_smoke
./tests/cuda_long_context_smoke
Expand All @@ -136,9 +136,12 @@ ds4_bench.o: ds4_bench.c ds4.h
ds4_eval.o: ds4_eval.c ds4.h
$(CC) $(CFLAGS) -c -o $@ ds4_eval.c

ds4_agent.o: ds4_agent.c ds4.h ds4_kvstore.h ds4_web.h linenoise.h
ds4_agent.o: ds4_agent.c ds4.h ds4_agent_git.h ds4_kvstore.h ds4_web.h linenoise.h
$(CC) $(CFLAGS) -c -o $@ ds4_agent.c

ds4_agent_git.o: ds4_agent_git.c ds4_agent_git.h
$(CC) $(CFLAGS) -c -o $@ ds4_agent_git.c

ds4_web.o: ds4_web.c ds4_web.h
$(CC) $(CFLAGS) -c -o $@ ds4_web.c

Expand All @@ -151,6 +154,9 @@ ds4_test.o: tests/ds4_test.c ds4_server.c ds4.h ds4_kvstore.h rax.h
tests/cuda_long_context_smoke.o: tests/cuda_long_context_smoke.c ds4_gpu.h
$(CC) $(CFLAGS) -I. -c -o $@ tests/cuda_long_context_smoke.c

tests/ds4_agent_git_test.o: tests/ds4_agent_git_test.c ds4_agent_git.h
$(CC) $(CFLAGS) -I. -c -o $@ tests/ds4_agent_git_test.c

rax.o: rax.c rax.h rax_malloc.h
$(CC) $(CFLAGS) -c -o $@ rax.c

Expand All @@ -172,7 +178,7 @@ ds4_bench_cpu.o: ds4_bench.c ds4.h
ds4_eval_cpu.o: ds4_eval.c ds4.h
$(CC) $(CFLAGS) -DDS4_NO_GPU -c -o $@ ds4_eval.c

ds4_agent_cpu.o: ds4_agent.c ds4.h ds4_kvstore.h ds4_web.h linenoise.h
ds4_agent_cpu.o: ds4_agent.c ds4.h ds4_agent_git.h ds4_kvstore.h ds4_web.h linenoise.h
$(CC) $(CFLAGS) -DDS4_NO_GPU -c -o $@ ds4_agent.c

ds4_metal.o: ds4_metal.m ds4_gpu.h $(METAL_SRCS)
Expand All @@ -184,16 +190,20 @@ ds4_cuda.o: ds4_cuda.cu ds4_gpu.h ds4_iq2_tables_cuda.inc
tests/cuda_long_context_smoke: tests/cuda_long_context_smoke.o ds4_cuda.o
$(NVCC) $(NVCCFLAGS) -o $@ $^ $(CUDA_LDLIBS)

tests/ds4_agent_git_test: tests/ds4_agent_git_test.o ds4_agent_git.o
$(CC) $(CFLAGS) -o $@ tests/ds4_agent_git_test.o ds4_agent_git.o $(LDLIBS)

ds4_test: ds4_test.o ds4_kvstore.o rax.o $(CORE_OBJS)
ifeq ($(UNAME_S),Darwin)
$(CC) $(CFLAGS) -o $@ ds4_test.o ds4_kvstore.o rax.o $(CORE_OBJS) $(METAL_LDLIBS)
else
$(NVCC) $(NVCCFLAGS) -o $@ ds4_test.o ds4_kvstore.o rax.o $(CORE_OBJS) $(CUDA_LDLIBS)
endif

test: ds4_test ds4-eval
test: ds4_test ds4-eval tests/ds4_agent_git_test
./ds4-eval --self-test-extractors
./tests/ds4_agent_git_test
./ds4_test

clean:
rm -f ds4 ds4-server ds4-bench ds4-eval ds4-agent ds4_cpu ds4_native ds4_server_test ds4_test *.o tests/cuda_long_context_smoke tests/cuda_long_context_smoke.o
rm -f ds4 ds4-server ds4-bench ds4-eval ds4-agent ds4_cpu ds4_native ds4_server_test ds4_test *.o tests/cuda_long_context_smoke tests/cuda_long_context_smoke.o tests/ds4_agent_git_test tests/ds4_agent_git_test.o
93 changes: 93 additions & 0 deletions docs/agent-git-tools.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
# Agent Git Tools

This branch keeps Git support independent from agent context/KV checkpointing.
The native `git` DSML tool is wired through `ds4_agent_git.c` and does not link
against `ds4_agent_context.c`.

## Goals

- Provide fast local repository inspection without shell parsing.
- Keep all argv construction direct through `fork`/`exec`, never through a shell.
- Bound output with `max_bytes` and reject unsafe paths, refs, remotes, and
messages before invoking Git.
- Run Git non-interactively: stdin is `/dev/null`, pagers/prompts/editors are
disabled, and every invocation has a bounded timeout.
- Allow guarded local mutations only when intent is explicit and validation
happens before invoking Git.
- Require interactive user approval for every real Git mutation; `dry_run`
calls and read-only inspection never prompt.
- Keep the riskiest local and remote mutations behind an additional
model-visible `confirm=true` intent flag unless the call is a `dry_run`.
- Keep merge and rebase conservative: preview first, clean worktree required,
and first real merge mode limited to `--ff-only`.

## Scope Status

The original MVP was read-only inspection. The implementation has deliberately
moved beyond that MVP into guarded local and remote operations because those
actions are needed for a useful branch-management loop.

This document is the authoritative scope for the Git branch. Older combined
planning text in the context/KV document is historical only after the split:
`feature/agent-git-tools` owns Git support, while
`feature/agent-kv-context-tools` owns context/KV checkpointing.

## Implemented Actions

The model-visible DSML schema enumerates the same action set so invalid action
names are rejected before the model has to infer command names from prose.

Read-only actions include `info`, `status`, `changed_files`, `diff`, `log`,
`show`, `ls_files`, `file_at_ref`, `blame`, `path_history`, `remote_list`,
`merge_base`, `merge_preview`, and `rebase_preview`.

Guarded local actions include `stage`, `unstage`, `commit`,
`worktree_restore`, `switch`, `stash_push`, `stash_apply`, `stash_pop`, and
`stash_drop`.

Guarded remote and integration actions include `fetch`, `push`, `merge`,
`merge_abort`, `rebase`, and `rebase_abort`.

## Guardrails

- Every Git subprocess defaults to `timeout_sec=30`; callers can request
`timeout_sec` from 1 to 600 seconds. A timeout kills the Git process group and
reports exit code 124 with a timeout notice in the tool output.
- Git runs with terminal prompts disabled (`GIT_TERMINAL_PROMPT=0`), askpass
helpers disabled, merge auto-edit disabled, and `GIT_EDITOR=true`.
- Every real mutating action prompts the local user before invoking Git.
In non-interactive mode, Git mutations are rejected.
- `stage` and `unstage` require either `path` or `all=true`.
- `commit` requires an explicit one-line `message`.
- `worktree_restore` requires either `path` or `all=true`, defaults `ref=HEAD`,
supports `dry_run`, and requires `confirm=true` for a real restore.
- `switch` requires an explicit safe `ref` and `confirm=true` for a real branch
switch; it does not create branches and does not use force, discard, or merge
flags.
- `stash_push` requires an explicit one-line `message`; `all=true` includes
untracked files.
- `stash_show`, `stash_apply`, `stash_pop`, and `stash_drop` accept only safe
stash refs such as `stash@{0}`.
- Real `stash_pop` and `stash_drop` require `confirm=true`; `stash_apply`
supports `dry_run` preview and leaves the stash entry intact.
- `fetch` requires an explicit `remote`; real fetch requires `confirm=true`.
- `push` requires explicit `remote` and `ref`; real push requires
`confirm=true`. Push rejects force, delete, and colon refspec syntax.
- `merge` requires an explicit target ref, `confirm=true` or `dry_run=true`,
and a clean working tree. Real merge is `git merge --ff-only <target>`.
- `rebase` requires an explicit upstream ref, `confirm=true` or `dry_run=true`,
and a clean working tree.
- `merge_abort` and `rebase_abort` require `confirm=true` or `dry_run=true`.
- Paths are passed after `--` where applicable.
- Refs, ranges, remotes, and push refs are rejected when they look like options
or unsupported refspecs.

## Non-Goals

- No `reset`.
- No `clean`.
- No raw `checkout`; branch movement uses the guarded `switch` action only.
- No force push.
- No branch/tag deletion.
- No non-fast-forward merge strategy in the first implementation.
- No dependency on context checkpoint or KV-cache internals.
Loading